Skip to content

Commit 112e006

Browse files
authored
fix: make GOAD lab plays idempotent and source bot passwords from config (#403)
fix: make lab scripts idempotent and pull secrets from config **Changed:** - Delegation scripts now query existing SPNs and `msDS-AllowedToDelegateTo` values before adding, only writing missing entries to avoid LDAP constraint violations that fail plays on lab reset - `constrained_delegation_kerb_only.ps1` and `constrained_delegation_use_any.ps1` for both GOAD and GOAD-Light - Scheduled task scripts now use `Register-ScheduledTask -Force` instead of manually checking for and unregistering existing tasks - `ntlm_relay.ps1`, `rdp_scheduler.ps1`, and `responder.ps1` for both GOAD and GOAD-Light - Hardcoded bot-account passwords replaced with Jinja references to lab config values, keeping secrets out of the scripts - The `ps` role now renders scripts via `lookup('template')` rather than `lookup('file')` so Jinja expressions such as config-sourced passwords are resolved before reaching the host - `ansible/roles/ps/tasks/main.yml`
1 parent d066243 commit 112e006

11 files changed

Lines changed: 91 additions & 49 deletions
Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,18 @@
11
# https://www.thehacker.recipes/ad/movement/kerberos/delegations/constrained#without-protocol-transition
2-
Set-ADComputer -Identity "castelblack$" -ServicePrincipalNames @{Add='HTTP/winterfell.north.sevenkingdoms.local'}
3-
Set-ADComputer -Identity "castelblack$" -Add @{'msDS-AllowedToDelegateTo'=@('HTTP/winterfell.north.sevenkingdoms.local','HTTP/winterfell')}
4-
# Set-ADComputer -Identity "castelblack$" -Add @{'msDS-AllowedToDelegateTo'=@('CIFS/winterfell.north.sevenkingdoms.local','CIFS/winterfell')}
2+
$identity = 'castelblack$'
3+
$spn = 'HTTP/winterfell.north.sevenkingdoms.local'
4+
$delegateTo = @('HTTP/winterfell.north.sevenkingdoms.local', 'HTTP/winterfell')
5+
# $delegateTo = @('CIFS/winterfell.north.sevenkingdoms.local', 'CIFS/winterfell')
6+
7+
# Re-adding a value a multi-valued attribute already holds is an LDAP constraint
8+
# violation, which fails the play on a lab reset, so only add what is missing.
9+
$computer = Get-ADComputer -Identity $identity -Properties ServicePrincipalNames, 'msDS-AllowedToDelegateTo'
10+
11+
if ($computer.ServicePrincipalNames -notcontains $spn) {
12+
Set-ADComputer -Identity $identity -ServicePrincipalNames @{Add = $spn }
13+
}
14+
15+
$missing = @($delegateTo | Where-Object { $computer.'msDS-AllowedToDelegateTo' -notcontains $_ })
16+
if ($missing.Count -gt 0) {
17+
Set-ADComputer -Identity $identity -Add @{'msDS-AllowedToDelegateTo' = $missing }
18+
}
Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,20 @@
11
# https://www.thehacker.recipes/ad/movement/kerberos/delegations/constrained#with-protocol-transition
2-
Set-ADUser -Identity "jon.snow" -ServicePrincipalNames @{Add='CIFS/winterfell.north.sevenkingdoms.local'}
3-
Get-ADUser -Identity "jon.snow" | Set-ADAccountControl -TrustedToAuthForDelegation $true
4-
Set-ADUser -Identity "jon.snow" -Add @{'msDS-AllowedToDelegateTo'=@('CIFS/winterfell.north.sevenkingdoms.local','CIFS/winterfell')}
2+
$identity = 'jon.snow'
3+
$spn = 'CIFS/winterfell.north.sevenkingdoms.local'
4+
$delegateTo = @('CIFS/winterfell.north.sevenkingdoms.local', 'CIFS/winterfell')
5+
6+
# Re-adding a value a multi-valued attribute already holds is an LDAP constraint
7+
# violation, which fails the play on a lab reset, so only add what is missing.
8+
# jon.snow already carries a kerberoastable SPN from ad-data: add, never replace.
9+
$user = Get-ADUser -Identity $identity -Properties ServicePrincipalNames, 'msDS-AllowedToDelegateTo'
10+
11+
if ($user.ServicePrincipalNames -notcontains $spn) {
12+
Set-ADUser -Identity $identity -ServicePrincipalNames @{Add = $spn }
13+
}
14+
15+
Set-ADAccountControl -Identity $identity -TrustedToAuthForDelegation $true
16+
17+
$missing = @($delegateTo | Where-Object { $user.'msDS-AllowedToDelegateTo' -notcontains $_ })
18+
if ($missing.Count -gt 0) {
19+
Set-ADUser -Identity $identity -Add @{'msDS-AllowedToDelegateTo' = $missing }
20+
}

ad/GOAD-Light/scripts/ntlm_relay.ps1

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,10 @@ $task = '/c powershell New-PSDrive -Name "Public" -PSProvider "FileSystem" -Root
22
$repeat = (New-TimeSpan -Minutes 5)
33
$taskName = "ntlm_bot"
44
$user = "north.sevenkingdoms.local\eddard.stark"
5-
$password = "FightP3aceAndHonor!"
5+
$password = "{{ lab.domains[lab.hosts.dc02.domain].users['eddard.stark'].password }}"
66

77
$action = New-ScheduledTaskAction -Execute "cmd.exe" -Argument "$task"
88
$trigger = New-ScheduledTaskTrigger -Once -At (Get-Date) -RepetitionInterval $repeat
99
$settings = New-ScheduledTaskSettingsSet -AllowStartIfOnBatteries -DontStopIfGoingOnBatteries -StartWhenAvailable -RunOnlyIfNetworkAvailable -DontStopOnIdleEnd
1010

11-
$taskExists = Get-ScheduledTask | Where-Object {$_.TaskName -like $taskName }
12-
if($taskExists) {
13-
Unregister-ScheduledTask -TaskName $taskName -Confirm:$false
14-
}
15-
Register-ScheduledTask -TaskName $taskName -Action $action -Trigger $trigger -User $user -Password $password -Settings $settings
11+
Register-ScheduledTask -TaskName $taskName -Action $action -Trigger $trigger -User $user -Password $password -Settings $settings -Force

ad/GOAD-Light/scripts/rdp_scheduler.ps1

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,10 @@ $task = '/c powershell c:\setup\bot_rdp.ps1'
22
$repeat = (New-TimeSpan -Minutes 1)
33
$taskName = "connect_bot"
44
$user = "north\robb.stark"
5-
$password = "sexywolfy"
5+
$password = "{{ lab.domains[lab.hosts.dc02.domain].users['robb.stark'].password }}"
66
$action = New-ScheduledTaskAction -Execute "cmd.exe" -Argument "$task"
77
$trigger = New-ScheduledTaskTrigger -Once -At (Get-Date) -RepetitionInterval $repeat
88
$settings = New-ScheduledTaskSettingsSet -AllowStartIfOnBatteries -DontStopIfGoingOnBatteries -StartWhenAvailable -RunOnlyIfNetworkAvailable -DontStopOnIdleEnd
99
#$settings.CimInstanceProperties.Item('MultipleInstances').Value = 3 # 3 corresponds to 'Stop the existing instance'
1010

11-
$taskExists = Get-ScheduledTask | Where-Object {$_.TaskName -like $taskName }
12-
if($taskExists) {
13-
Unregister-ScheduledTask -TaskName $taskName -Confirm:$false
14-
}
15-
Register-ScheduledTask -TaskName $taskName -Action $action -Trigger $trigger -User $user -Password $password -Settings $settings
11+
Register-ScheduledTask -TaskName $taskName -Action $action -Trigger $trigger -User $user -Password $password -Settings $settings -Force

ad/GOAD-Light/scripts/responder.ps1

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,10 @@ $task = '/c powershell New-PSDrive -Name "Public" -PSProvider "FileSystem" -Root
22
$repeat = (New-TimeSpan -Minutes 2)
33
$taskName = "responder_bot"
44
$user = "north.sevenkingdoms.local\robb.stark"
5-
$password = "sexywolfy"
5+
$password = "{{ lab.domains[lab.hosts.dc02.domain].users['robb.stark'].password }}"
66

77
$action = New-ScheduledTaskAction -Execute "cmd.exe" -Argument "$task"
88
$trigger = New-ScheduledTaskTrigger -Once -At (Get-Date) -RepetitionInterval $repeat
99
$settings = New-ScheduledTaskSettingsSet -AllowStartIfOnBatteries -DontStopIfGoingOnBatteries -StartWhenAvailable -RunOnlyIfNetworkAvailable -DontStopOnIdleEnd
1010

11-
$taskExists = Get-ScheduledTask | Where-Object {$_.TaskName -like $taskName }
12-
if($taskExists) {
13-
Unregister-ScheduledTask -TaskName $taskName -Confirm:$false
14-
}
15-
Register-ScheduledTask -TaskName $taskName -Action $action -Trigger $trigger -User $user -Password $password -Settings $settings
11+
Register-ScheduledTask -TaskName $taskName -Action $action -Trigger $trigger -User $user -Password $password -Settings $settings -Force
Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,18 @@
11
# https://www.thehacker.recipes/ad/movement/kerberos/delegations/constrained#without-protocol-transition
2-
Set-ADComputer -Identity "castelblack$" -ServicePrincipalNames @{Add='HTTP/winterfell.north.sevenkingdoms.local'}
3-
Set-ADComputer -Identity "castelblack$" -Add @{'msDS-AllowedToDelegateTo'=@('HTTP/winterfell.north.sevenkingdoms.local','HTTP/winterfell')}
4-
# Set-ADComputer -Identity "castelblack$" -Add @{'msDS-AllowedToDelegateTo'=@('CIFS/winterfell.north.sevenkingdoms.local','CIFS/winterfell')}
2+
$identity = 'castelblack$'
3+
$spn = 'HTTP/winterfell.north.sevenkingdoms.local'
4+
$delegateTo = @('HTTP/winterfell.north.sevenkingdoms.local', 'HTTP/winterfell')
5+
# $delegateTo = @('CIFS/winterfell.north.sevenkingdoms.local', 'CIFS/winterfell')
6+
7+
# Re-adding a value a multi-valued attribute already holds is an LDAP constraint
8+
# violation, which fails the play on a lab reset, so only add what is missing.
9+
$computer = Get-ADComputer -Identity $identity -Properties ServicePrincipalNames, 'msDS-AllowedToDelegateTo'
10+
11+
if ($computer.ServicePrincipalNames -notcontains $spn) {
12+
Set-ADComputer -Identity $identity -ServicePrincipalNames @{Add = $spn }
13+
}
14+
15+
$missing = @($delegateTo | Where-Object { $computer.'msDS-AllowedToDelegateTo' -notcontains $_ })
16+
if ($missing.Count -gt 0) {
17+
Set-ADComputer -Identity $identity -Add @{'msDS-AllowedToDelegateTo' = $missing }
18+
}
Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,19 @@
1-
Set-ADUser -Identity "jon.snow" -ServicePrincipalNames @{Add='CIFS/thewall.north.sevenkingdoms.local'}
2-
Get-ADUser -Identity "jon.snow" | Set-ADAccountControl -TrustedToAuthForDelegation $true
3-
Set-ADUser -Identity "jon.snow" -Add @{'msDS-AllowedToDelegateTo'=@('CIFS/winterfell.north.sevenkingdoms.local','CIFS/winterfell')}
1+
$identity = 'jon.snow'
2+
$spn = 'CIFS/thewall.north.sevenkingdoms.local'
3+
$delegateTo = @('CIFS/winterfell.north.sevenkingdoms.local', 'CIFS/winterfell')
4+
5+
# Re-adding a value a multi-valued attribute already holds is an LDAP constraint
6+
# violation, which fails the play on a lab reset, so only add what is missing.
7+
# jon.snow already carries a kerberoastable SPN from ad-data: add, never replace.
8+
$user = Get-ADUser -Identity $identity -Properties ServicePrincipalNames, 'msDS-AllowedToDelegateTo'
9+
10+
if ($user.ServicePrincipalNames -notcontains $spn) {
11+
Set-ADUser -Identity $identity -ServicePrincipalNames @{Add = $spn }
12+
}
13+
14+
Set-ADAccountControl -Identity $identity -TrustedToAuthForDelegation $true
15+
16+
$missing = @($delegateTo | Where-Object { $user.'msDS-AllowedToDelegateTo' -notcontains $_ })
17+
if ($missing.Count -gt 0) {
18+
Set-ADUser -Identity $identity -Add @{'msDS-AllowedToDelegateTo' = $missing }
19+
}

ad/GOAD/scripts/ntlm_relay.ps1

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,10 @@ $task = '/c powershell New-PSDrive -Name "Public" -PSProvider "FileSystem" -Root
22
$repeat = (New-TimeSpan -Minutes 5)
33
$taskName = "ntlm_bot"
44
$user = "north.sevenkingdoms.local\eddard.stark"
5-
$password = "FightP3aceAndHonor!"
5+
$password = "{{ lab.domains[lab.hosts.dc02.domain].users['eddard.stark'].password }}"
66

77
$action = New-ScheduledTaskAction -Execute "cmd.exe" -Argument "$task"
88
$trigger = New-ScheduledTaskTrigger -Once -At (Get-Date) -RepetitionInterval $repeat
99
$settings = New-ScheduledTaskSettingsSet -AllowStartIfOnBatteries -DontStopIfGoingOnBatteries -StartWhenAvailable -RunOnlyIfNetworkAvailable -DontStopOnIdleEnd
1010

11-
$taskExists = Get-ScheduledTask | Where-Object {$_.TaskName -like $taskName }
12-
if($taskExists) {
13-
Unregister-ScheduledTask -TaskName $taskName -Confirm:$false
14-
}
15-
Register-ScheduledTask -TaskName $taskName -Action $action -Trigger $trigger -User $user -Password $password -Settings $settings
11+
Register-ScheduledTask -TaskName $taskName -Action $action -Trigger $trigger -User $user -Password $password -Settings $settings -Force

ad/GOAD/scripts/rdp_scheduler.ps1

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,10 @@ $task = '/c powershell c:\setup\bot_rdp.ps1'
22
$repeat = (New-TimeSpan -Minutes 1)
33
$taskName = "connect_bot"
44
$user = "north\robb.stark"
5-
$password = "sexywolfy"
5+
$password = "{{ lab.domains[lab.hosts.dc02.domain].users['robb.stark'].password }}"
66
$action = New-ScheduledTaskAction -Execute "cmd.exe" -Argument "$task"
77
$trigger = New-ScheduledTaskTrigger -Once -At (Get-Date) -RepetitionInterval $repeat
88
$settings = New-ScheduledTaskSettingsSet -AllowStartIfOnBatteries -DontStopIfGoingOnBatteries -StartWhenAvailable -RunOnlyIfNetworkAvailable -DontStopOnIdleEnd
99
#$settings.CimInstanceProperties.Item('MultipleInstances').Value = 3 # 3 corresponds to 'Stop the existing instance'
1010

11-
$taskExists = Get-ScheduledTask | Where-Object {$_.TaskName -like $taskName }
12-
if($taskExists) {
13-
Unregister-ScheduledTask -TaskName $taskName -Confirm:$false
14-
}
15-
Register-ScheduledTask -TaskName $taskName -Action $action -Trigger $trigger -User $user -Password $password -Settings $settings
11+
Register-ScheduledTask -TaskName $taskName -Action $action -Trigger $trigger -User $user -Password $password -Settings $settings -Force

ad/GOAD/scripts/responder.ps1

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,10 @@ $task = '/c powershell New-PSDrive -Name "Public" -PSProvider "FileSystem" -Root
22
$repeat = (New-TimeSpan -Minutes 2)
33
$taskName = "responder_bot"
44
$user = "north.sevenkingdoms.local\robb.stark"
5-
$password = "sexywolfy"
5+
$password = "{{ lab.domains[lab.hosts.dc02.domain].users['robb.stark'].password }}"
66

77
$action = New-ScheduledTaskAction -Execute "cmd.exe" -Argument "$task"
88
$trigger = New-ScheduledTaskTrigger -Once -At (Get-Date) -RepetitionInterval $repeat
99
$settings = New-ScheduledTaskSettingsSet -AllowStartIfOnBatteries -DontStopIfGoingOnBatteries -StartWhenAvailable -RunOnlyIfNetworkAvailable -DontStopOnIdleEnd
1010

11-
$taskExists = Get-ScheduledTask | Where-Object {$_.TaskName -like $taskName }
12-
if($taskExists) {
13-
Unregister-ScheduledTask -TaskName $taskName -Confirm:$false
14-
}
15-
Register-ScheduledTask -TaskName $taskName -Action $action -Trigger $trigger -User $user -Password $password -Settings $settings
11+
Register-ScheduledTask -TaskName $taskName -Action $action -Trigger $trigger -User $user -Password $password -Settings $settings -Force

0 commit comments

Comments
 (0)