Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 18 additions & 0 deletions EntraGoatGUI/Data/Challenges.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,24 @@ function Get-EntraGoatChallenges {
'Try enabling CBA with one SP, then use another to upload a trusted root CA and forge your way in. No password? No problem.'
)
}
@{
Id = 7
Title = 'Legacy Loophole - When MFA Forgot the Side Door'
Description = "Raj Patel runs the messaging stack and remembers every helpdesk shortcut the team ever cut. The tenant rolled out a 'Require MFA for All Users' Conditional Access policy last quarter, but the messaging admin account still answers IMAP and SMTP AUTH for an old line-of-business mailbox. Find the gap in the policy, ride a legacy-auth path past MFA, and lift the flag from the admin's profile."
Difficulty = 'Beginner'
Flag = 'EntraGoat{L3g@cy_4uth_C0nd1t10n@l_Byp@ss_Pwn3d!}'
StartingCredentials = [ordered]@{
Username = 'raj.patel@yourtenant.onmicrosoft.com'
Password = 'GoatAccess!123'
}
Hints = @(
'Conditional Access scopes "client app types" as an allow-list. Look at what is actually scoped.'
'Modern auth and legacy auth are NOT the same channel for CA evaluation.'
'ROPC, IMAP, POP, SMTP AUTH and ActiveSync are all "legacy" - any of them will do.'
'Helpdesk reset passwords have a habit of sticking around.'
'Microsoft publishes a "Block legacy authentication" CA template for a reason.'
)
}
)
@{ Challenges = $Challenges }
}
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ cd scenarios
| 4 | I (Eligibly) Own That | Intermediate |
| 5 | Department of Escalations - AU Ready for This? | Advanced |
| 6 | CBA (Certificate Bypass Authority) - Root Access Granted | Advanced |
| 7 | Legacy Loophole — When MFA Forgot the Side Door | Beginner |

Each scenario includes a setup script, cleanup script, solution walkthrough, and a hidden flag.

Expand Down
141 changes: 141 additions & 0 deletions cleanups/EntraGoat-Scenario7-Cleanup.ps1
Original file line number Diff line number Diff line change
@@ -0,0 +1,141 @@
<#
.SYNOPSIS
EntraGoat Scenario 7: Cleanup Script
To be run with Global Administrator privileges.

.DESCRIPTION
Cleans up:
- Users (raj.patel, EntraGoat-admin-s7)
- Conditional Access policy ("EntraGoat S7 - Require MFA for All Users")
- Directory role assignments tied to the deleted admin
#>

# Requires -Modules Microsoft.Graph.Authentication, Microsoft.Graph.Users, Microsoft.Graph.Identity.DirectoryManagement, Microsoft.Graph.Identity.SignIns


[CmdletBinding()]
param(
[Parameter(Mandatory=$false)]
[string]$TenantId = $null
)

$CAPolicyName = "EntraGoat S7 - Require MFA for All Users"

$RequiredScopes = @(
"User.ReadWrite.All",
"Directory.ReadWrite.All",
"RoleManagement.ReadWrite.Directory",
"Policy.ReadWrite.ConditionalAccess"
)

Write-Host ""
Write-Host "|--------------------------------------------------------------|" -ForegroundColor Cyan
Write-Host "| ENTRAGOAT SCENARIO 7 - CLEANUP PROCESS |" -ForegroundColor Cyan
Write-Host "|--------------------------------------------------------------|" -ForegroundColor Cyan
Write-Host ""

#region Module Check and Import
Write-Verbose "[*] Checking required Microsoft Graph modules..."
$RequiredCleanupModules = @("Microsoft.Graph.Authentication", "Microsoft.Graph.Users", "Microsoft.Graph.Identity.DirectoryManagement", "Microsoft.Graph.Identity.SignIns")
foreach ($moduleName in $RequiredCleanupModules) {
try {
Import-Module $moduleName -ErrorAction SilentlyContinue -Verbose:$false
if (-not (Get-Module -Name $moduleName -ErrorAction SilentlyContinue -Verbose:$false)) {
throw "Failed to import $moduleName"
}
Write-Verbose "[+] Imported module $moduleName."
} catch {
Write-Host "[-] " -ForegroundColor Red -NoNewline
Write-Host "Failed to import module $moduleName. Please ensure Microsoft Graph SDK is installed. Error: $($_.Exception.Message)" -ForegroundColor White
exit 1
}
}
#endregion

# Connect to Microsoft Graph
if ($TenantId) {
Connect-MgGraph -Scopes $RequiredScopes -TenantId $TenantId -NoWelcome
} else {
Connect-MgGraph -Scopes $RequiredScopes -NoWelcome
}

# Get Tenant Domain
$Organization = Get-MgOrganization
$TenantDomain = ($Organization.VerifiedDomains | Where-Object IsDefault).Name

# Target Objects
$LowPrivUPN = "raj.patel@$TenantDomain"
$AdminUPN = "EntraGoat-admin-s7@$TenantDomain"

# Cleanup Conditional Access Policy first - cheap and isolated
Write-Host "`n[*] Removing Conditional Access policy..." -ForegroundColor Cyan
$CAPolicy = Get-MgIdentityConditionalAccessPolicy -Filter "displayName eq '$CAPolicyName'" -ErrorAction SilentlyContinue
if ($CAPolicy) {
try {
Remove-MgIdentityConditionalAccessPolicy -ConditionalAccessPolicyId $CAPolicy.Id -ErrorAction Stop
Write-Host " [+] Deleted CA policy: $CAPolicyName" -ForegroundColor Green
} catch {
Write-Host " [-] Failed to delete CA policy: $($_.Exception.Message)" -ForegroundColor Red
}
} else {
Write-Host " [-] CA policy not found: $CAPolicyName" -ForegroundColor Yellow
}

# Cleanup Users
Write-Host "`n[*] Removing users..." -ForegroundColor Cyan

foreach ($UserUPN in @($LowPrivUPN, $AdminUPN)) {
Write-Verbose " -> Checking user: $UserUPN"
$User = Get-MgUser -Filter "userPrincipalName eq '$UserUPN'" -ErrorAction SilentlyContinue
if ($User) {
try {
Remove-MgUser -UserId $User.Id -Confirm:$false
Write-Host " [+] Deleted user: $UserUPN" -ForegroundColor Green
} catch {
Write-Host " [-] Failed to delete user: $UserUPN - $($_.Exception.Message)" -ForegroundColor Red
}
} else {
Write-Host " [-] User not found: $UserUPN" -ForegroundColor Yellow
}
}

# Wait until all target objects are truly deleted before proceeding
function Wait-ForAllDeletions {
param (
[array]$ObjectsToCheck,
[int]$TimeoutSeconds = 60
)
$sw = [System.Diagnostics.Stopwatch]::StartNew()
while ($sw.Elapsed.TotalSeconds -lt $TimeoutSeconds) {
$allDeleted = $true

foreach ($obj in $ObjectsToCheck) {
if ($obj.Type -eq "User") {
$exists = Get-MgUser -Filter "userPrincipalName eq '$($obj.UPN)'" -ErrorAction SilentlyContinue
if ($exists) { $allDeleted = $false }
} elseif ($obj.Type -eq "CAPolicy") {
$polExists = Get-MgIdentityConditionalAccessPolicy -Filter "displayName eq '$($obj.Name)'" -ErrorAction SilentlyContinue
if ($polExists) { $allDeleted = $false }
}
}

if ($allDeleted) {
Write-Host "`n[+] Confirmed inexistence of all requested objects" -ForegroundColor DarkGreen
return
}
Start-Sleep -Seconds 15
}
Write-Host "[-] Warning: Timed out waiting for deletion of some objects." -ForegroundColor Yellow
}

Write-Host "`n[*] Waiting for objects to be fully purged (this can take a moment)..." -ForegroundColor Cyan
$objectsToCheck = @(
@{ Type = "User"; UPN = $LowPrivUPN },
@{ Type = "User"; UPN = $AdminUPN },
@{ Type = "CAPolicy"; Name = $CAPolicyName }
)
Wait-ForAllDeletions -ObjectsToCheck $objectsToCheck

Write-Host "`nCleanup process for Scenario 7 complete." -ForegroundColor White
Write-Host "=====================================================" -ForegroundColor DarkGray
Write-Host ""
1 change: 1 addition & 0 deletions docs/challenges.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ EntraGoat ships with 6 privilege escalation scenarios of increasing difficulty.
| 4 | The Eligible Menace — PIM Path to Power | Intermediate | Privileged Identity Management abuse |
| 5 | AU to Admin — The Restricted Path | Advanced | Administrative Unit boundary escape |
| 6 | Certificate of Insanity — Trusting the Wrong Authority | Advanced | Certificate-based authentication impersonation |
| 7 | Legacy Loophole — When MFA Forgot the Side Door | Beginner | Conditional Access bypass via legacy authentication |

## How to play

Expand Down
141 changes: 141 additions & 0 deletions frontend/public/scripts/challenge7/cleanup.ps1
Original file line number Diff line number Diff line change
@@ -0,0 +1,141 @@
<#
.SYNOPSIS
EntraGoat Scenario 7: Cleanup Script
To be run with Global Administrator privileges.

.DESCRIPTION
Cleans up:
- Users (raj.patel, EntraGoat-admin-s7)
- Conditional Access policy ("EntraGoat S7 - Require MFA for All Users")
- Directory role assignments tied to the deleted admin
#>

# Requires -Modules Microsoft.Graph.Authentication, Microsoft.Graph.Users, Microsoft.Graph.Identity.DirectoryManagement, Microsoft.Graph.Identity.SignIns


[CmdletBinding()]
param(
[Parameter(Mandatory=$false)]
[string]$TenantId = $null
)

$CAPolicyName = "EntraGoat S7 - Require MFA for All Users"

$RequiredScopes = @(
"User.ReadWrite.All",
"Directory.ReadWrite.All",
"RoleManagement.ReadWrite.Directory",
"Policy.ReadWrite.ConditionalAccess"
)

Write-Host ""
Write-Host "|--------------------------------------------------------------|" -ForegroundColor Cyan
Write-Host "| ENTRAGOAT SCENARIO 7 - CLEANUP PROCESS |" -ForegroundColor Cyan
Write-Host "|--------------------------------------------------------------|" -ForegroundColor Cyan
Write-Host ""

#region Module Check and Import
Write-Verbose "[*] Checking required Microsoft Graph modules..."
$RequiredCleanupModules = @("Microsoft.Graph.Authentication", "Microsoft.Graph.Users", "Microsoft.Graph.Identity.DirectoryManagement", "Microsoft.Graph.Identity.SignIns")
foreach ($moduleName in $RequiredCleanupModules) {
try {
Import-Module $moduleName -ErrorAction SilentlyContinue -Verbose:$false
if (-not (Get-Module -Name $moduleName -ErrorAction SilentlyContinue -Verbose:$false)) {
throw "Failed to import $moduleName"
}
Write-Verbose "[+] Imported module $moduleName."
} catch {
Write-Host "[-] " -ForegroundColor Red -NoNewline
Write-Host "Failed to import module $moduleName. Please ensure Microsoft Graph SDK is installed. Error: $($_.Exception.Message)" -ForegroundColor White
exit 1
}
}
#endregion

# Connect to Microsoft Graph
if ($TenantId) {
Connect-MgGraph -Scopes $RequiredScopes -TenantId $TenantId -NoWelcome
} else {
Connect-MgGraph -Scopes $RequiredScopes -NoWelcome
}

# Get Tenant Domain
$Organization = Get-MgOrganization
$TenantDomain = ($Organization.VerifiedDomains | Where-Object IsDefault).Name

# Target Objects
$LowPrivUPN = "raj.patel@$TenantDomain"
$AdminUPN = "EntraGoat-admin-s7@$TenantDomain"

# Cleanup Conditional Access Policy first - cheap and isolated
Write-Host "`n[*] Removing Conditional Access policy..." -ForegroundColor Cyan
$CAPolicy = Get-MgIdentityConditionalAccessPolicy -Filter "displayName eq '$CAPolicyName'" -ErrorAction SilentlyContinue
if ($CAPolicy) {
try {
Remove-MgIdentityConditionalAccessPolicy -ConditionalAccessPolicyId $CAPolicy.Id -ErrorAction Stop
Write-Host " [+] Deleted CA policy: $CAPolicyName" -ForegroundColor Green
} catch {
Write-Host " [-] Failed to delete CA policy: $($_.Exception.Message)" -ForegroundColor Red
}
} else {
Write-Host " [-] CA policy not found: $CAPolicyName" -ForegroundColor Yellow
}

# Cleanup Users
Write-Host "`n[*] Removing users..." -ForegroundColor Cyan

foreach ($UserUPN in @($LowPrivUPN, $AdminUPN)) {
Write-Verbose " -> Checking user: $UserUPN"
$User = Get-MgUser -Filter "userPrincipalName eq '$UserUPN'" -ErrorAction SilentlyContinue
if ($User) {
try {
Remove-MgUser -UserId $User.Id -Confirm:$false
Write-Host " [+] Deleted user: $UserUPN" -ForegroundColor Green
} catch {
Write-Host " [-] Failed to delete user: $UserUPN - $($_.Exception.Message)" -ForegroundColor Red
}
} else {
Write-Host " [-] User not found: $UserUPN" -ForegroundColor Yellow
}
}

# Wait until all target objects are truly deleted before proceeding
function Wait-ForAllDeletions {
param (
[array]$ObjectsToCheck,
[int]$TimeoutSeconds = 60
)
$sw = [System.Diagnostics.Stopwatch]::StartNew()
while ($sw.Elapsed.TotalSeconds -lt $TimeoutSeconds) {
$allDeleted = $true

foreach ($obj in $ObjectsToCheck) {
if ($obj.Type -eq "User") {
$exists = Get-MgUser -Filter "userPrincipalName eq '$($obj.UPN)'" -ErrorAction SilentlyContinue
if ($exists) { $allDeleted = $false }
} elseif ($obj.Type -eq "CAPolicy") {
$polExists = Get-MgIdentityConditionalAccessPolicy -Filter "displayName eq '$($obj.Name)'" -ErrorAction SilentlyContinue
if ($polExists) { $allDeleted = $false }
}
}

if ($allDeleted) {
Write-Host "`n[+] Confirmed inexistence of all requested objects" -ForegroundColor DarkGreen
return
}
Start-Sleep -Seconds 15
}
Write-Host "[-] Warning: Timed out waiting for deletion of some objects." -ForegroundColor Yellow
}

Write-Host "`n[*] Waiting for objects to be fully purged (this can take a moment)..." -ForegroundColor Cyan
$objectsToCheck = @(
@{ Type = "User"; UPN = $LowPrivUPN },
@{ Type = "User"; UPN = $AdminUPN },
@{ Type = "CAPolicy"; Name = $CAPolicyName }
)
Wait-ForAllDeletions -ObjectsToCheck $objectsToCheck

Write-Host "`nCleanup process for Scenario 7 complete." -ForegroundColor White
Write-Host "=====================================================" -ForegroundColor DarkGray
Write-Host ""
Loading