Enterprise Lab

Hybrid Active Directory Enterprise Lab

A multi-cloud lab environment built across Vultr, Oracle Cloud, and AWS. Active Directory forest with a child domain, WireGuard mesh VPN stitching everything together, Exchange Server 2019, Azure Entra ID hybrid identity sync, and a set of deliberate misconfigurations to practice real attack paths.

7 Machines
3 Cloud Providers
50+ AD Users
6 Attack Paths
Hybrid Active Directory Enterprise Lab architecture overview
Multi-cloud hybrid AD lab spanning Vultr, Oracle Cloud, and AWS

Overview

The goal of this lab was to build something close to a real enterprise environment — not just a single Windows server running AD in a home lab. It spans three cloud providers, uses a proper WireGuard mesh to connect them all, has a real mail server, real hybrid cloud identity, and a realistic set of misconfigurations that mirror what you actually find in penetration tests.

Everything here was built manually, step by step, including all the errors that came up along the way. The domain is apex-corp.xyz and the internal forest root is hq.apex-corp.xyz. Characters are named after MCU, DCU, and The Boys cast to make the user accounts look like a real company.

Lab Purpose

This is a personal training lab and portfolio project. All systems are isolated and under personal control. The misconfigurations are intentional, documented, and meant to simulate realistic enterprise attack surfaces for learning purposes.

Tech Stack

Windows Server 2022
Ubuntu 24.04 LTS
WireGuard VPN
Vultr VPS
Oracle Cloud
AWS EC2
Exchange 2019
Azure Entra ID
Jenkins
AD CS
Cloudflare DNS
Flask + Gunicorn

Architecture

All machines connect through a WireGuard mesh VPN. The Domain Controller on Vultr (10.10.0.1) acts as the hub. Every machine uses it as its primary DNS, which means Active Directory resolution works across all three cloud providers.

Part 1: High-Level Infrastructure Overview

A conceptual mapping of how the cloud-hosted environments (Vultr, Oracle, AWS) interconnect via the WireGuard VPN mesh, and how they synchronize identity to the Azure cloud directory.

graph TD VULTR["☁️ Vultr Cloud (Primary Core)"] ORACLE["☁️ Oracle Cloud (Child Subnet)"] AWS["☁️ AWS EC2 (Public Security Border)"] AZURE["☁️ Microsoft Azure (Identity Hub)"] VULTR <-->|"WireGuard Mesh VPN"| ORACLE VULTR <-->|"WireGuard Mesh VPN"| AWS VULTR -->|"Microsoft Entra Connect PHS Sync"| AZURE style VULTR fill:#1d252c,stroke:#a4ff91,stroke-width:2px,color:#fff style ORACLE fill:#1d252c,stroke:#ffaa44,stroke-width:2px,color:#fff style AWS fill:#1d252c,stroke:#ff6b6b,stroke-width:2px,color:#fff style AZURE fill:#1d252c,stroke:#9988ff,stroke-width:2px,color:#fff

Part 2A: Vultr Core Internal Network

The Vultr datacenter hosts the primary domain controller alongside supporting servers. APEX-PORTAL and MAILSERVER depend on STARK-TOWER for DNS and directory authentication, while FLATIRON provides a domain-joined workstation for user simulation.

graph LR DC01["🖥️ STARK-TOWER (DC01)
Root DC · AD CS · DNS
10.10.0.1"] EXCH01["📧 MAILSERVER (EXCH01)
Exchange Server 2019"] PORTAL["🌐 APEX-PORTAL (PORTAL01)
Flask Web App"] WS01["💻 FLATIRON (WS01)
Win10 Workstation
h.campbell session"] EXCH01 --- DC01 PORTAL --- DC01 WS01 -.->|"domain-joined"| DC01 style DC01 fill:#1a3a1a,stroke:#a4ff91,color:#fff style EXCH01 fill:#1a2a3a,stroke:#6bb5ff,color:#fff style PORTAL fill:#1a2a3a,stroke:#6bb5ff,color:#fff style WS01 fill:#1a2a2a,stroke:#44ffcc,color:#fff

Part 2B: Multi-Cloud VPN Mesh (WireGuard)

STARK-TOWER acts as the WireGuard hub, stitching remote cloud providers into a single private subnet (10.10.0.0/24). Each peer connects directly to the hub for AD resolution and inter-cloud communication.

graph TB HUB["🖥️ STARK-TOWER (DC01)
WireGuard Hub · DNS
10.10.0.1"] P2["🖥️ VOUGHT-HQ (DC02)
Oracle Cloud · Child DC
10.10.0.2"] P3["🐧 BATCAVE (LINUX01)
Oracle Cloud · Ubuntu
10.10.0.3"] P5["🐧 WATCHTOWER (LINUX02)
AWS EC2 · Jenkins
10.10.0.5"] HUB <-->|"WireGuard"| P2 HUB <-->|"WireGuard"| P3 HUB <-->|"WireGuard"| P5 style HUB fill:#1a3a1a,stroke:#a4ff91,color:#fff style P2 fill:#3a2a1a,stroke:#ffaa44,color:#fff style P3 fill:#3a2a1a,stroke:#ffaa44,color:#fff style P5 fill:#3a1a1a,stroke:#ff6b6b,color:#fff

Part 3: Hybrid Cloud Identity & Auth Flow

Illustrating user credential and identity flows. Local AD credentials from the Vultr VPS sync up to Microsoft Entra ID. The web portal authenticates users externally against Entra ID and logs session history in Cosmos DB.

graph LR subgraph ONPREM ["Active Directory Domain Controller"] DC01["🖥️ STARK-TOWER (DC01)
Domain Controller (hq.apex-corp.xyz)"] end subgraph AZURE ["☁️ Microsoft Azure"] ENTRA["☁️ Microsoft Entra ID
apex-corp.xyz Tenant"] COSMOS["🗄️ Cosmos DB
User Metadata Backend"] end subgraph WEBPORTAL ["External User Flow"] PORTAL["🌐 APEX-PORTAL (PORTAL01)
portal.apex-corp.xyz"] end DC01 -->|"Password Hash Sync (PHS)
via Microsoft Entra Connect"| ENTRA PORTAL -->|"OAuth2 User Login"| ENTRA PORTAL -->|"Read/Write Session Data"| COSMOS style DC01 fill:#1a3a1a,stroke:#a4ff91,color:#fff style ENTRA fill:#1a1a3a,stroke:#9988ff,color:#fff style COSMOS fill:#1a1a3a,stroke:#9988ff,color:#fff style PORTAL fill:#1a2a3a,stroke:#6bb5ff,color:#fff

Machine Inventory

Hostname OS Role WireGuard IP Cloud Status
STARK-TOWER (DC01) Windows Server 2022 Root DC, AD CS, DNS, WireGuard Hub, AD Connect 10.10.0.1 Vultr Active
MAILSERVER (EXCH01) Windows Server 2022 Exchange 2019 — OWA, SMTP, EWS, MAPI via DC01 gateway Vultr Active
APEX-PORTAL (PORTAL01) Ubuntu 24.04 Flask OAuth Portal — Caddy, Gunicorn, Cosmos DB via DC01 gateway Vultr Active
FLATIRON (WS01) Windows 10 Pro Domain workstation — user session h.campbell 10.10.0.4 Vultr Active
WATCHTOWER (LINUX02) Ubuntu 24.04 Jenkins :8080 — planted creds, vuln config 10.10.0.5 AWS EC2 Active
VOUGHT-HQ (DC02) Windows Server 2022 Child DC — vought.hq.apex-corp.xyz, MSSQL, IIS 10.10.0.2 Oracle Cloud Decommissioned
BATCAVE (LINUX01) Ubuntu 24.04 AD-joined Linux — Nginx, PostgreSQL, Docker 10.10.0.3 Oracle Cloud Decommissioned
Note on Oracle machines

VOUGHT-HQ and BATCAVE run on Oracle Cloud free-tier instances and are fully operational within the WireGuard mesh. The child domain vought.hq.apex-corp.xyz is active and joined to the forest. All configurations are fully documented and reproducible.

Network Layout

graph LR subgraph INTERNET ["Public Internet"] CF["☁️ Cloudflare DNS
apex-corp.xyz
DNS only — no proxy
on SMTP / mail records"] end subgraph VPN ["WireGuard VPN — 10.10.0.0/24"] HUB["DC01
10.10.0.1
Hub + DNS"] P2["DC02 10.10.0.2"] P3["LINUX01 10.10.0.3"] P4["WS01 10.10.0.4"] P5["LINUX02 10.10.0.5"] end CF -->|"A record → Vultr Public IP"| HUB HUB --- P2 HUB --- P3 HUB --- P4 HUB --- P5 style HUB fill:#1a3a1a,stroke:#a4ff91,color:#fff
DNS Record Type Points To Proxy
apex-corp.xyzAVultr Public IP (DC01)DNS only
mail.apex-corp.xyzAVultr Public IP (EXCH01)DNS only ⚠️
portal.apex-corp.xyzAPortal VPS Public IPDNS only
autodiscover.apex-corp.xyzCNAMEmail.apex-corp.xyzDNS only ⚠️
@ (MX)MXmail.apex-corp.xyz priority 10
@ (SPF)TXTv=spf1 a:mail.apex-corp.xyz ~all

Users & Groups

The domain has around 50 named user accounts spread across realistic Organizational Units. Characters are pulled from MCU, DCU, and The Boys to make the environment look like an actual company. A selection of key accounts:

Username Name OU Privilege Notes
t.stark Tony Stark Executives Domain Admin Main admin — Enterprise Admin, Schema Admin
homelander John Gillman Executives Domain Admin Intentional DA misconfiguration on child domain
svc_alfred svc_alfred Service Accounts Service Acct Kerberoastable — SPN set, GenericAll on Domain Admins
svc_jarvis svc_jarvis Service Accounts Service Acct Kerberoastable — HTTP SPN, creds in Jenkins
svc_friday svc_friday Service Accounts Service Acct Kerberoastable — creds in Jenkins workspace
h.campbell Hughie Campbell Operations Standard User Active workstation session on WS01 (FLATIRON)
b.allen Barry Allen IT Department Standard User Jenkins admin account — brute-forceable

Service accounts have Kerberos Service Principal Names (SPNs) registered, making them targets for Kerberoasting. Several standard users have the "Do not require Kerberos preauthentication" box checked, making them AS-REPRoastable.

Attack Paths

The lab is designed so an attacker can move from a public foothold all the way to Domain Admin and cloud access. The full chain:

graph TD A["🌐 Public Internet
Jenkins :8080 on WATCHTOWER
No authentication on People API"] -->|"User enumeration
anonymous read"| B["👤 b.allen discovered
/people/api/json"] B -->|"Hydra brute force
rockyou.txt"| C["🔑 Jenkins login
b.allen / Flash4Ever!"] C -->|"Groovy Script Console
Read workspace files"| D["📄 svc_jarvis creds
J@rv1s2025! — in deploy.sh
svc_friday creds — in .env"] D -->|"Kerberoast SPNs
or use plaintext creds"| E["🎫 TGS tickets
offline crack OR
direct AD auth"] E -->|"Exchange WriteDACL
abuse via MAILSERVER$"| F["🏰 Domain Admin
hq.apex-corp.xyz"] F -->|"Password Hash Sync
Entra Connect"| G["☁️ Cloud Access
Entra ID tenant
portal.apex-corp.xyz
Azure services"] style A fill:#2a1a1a,stroke:#ff6b6b,color:#fff style F fill:#3a1a1a,stroke:#ff4444,color:#fff style G fill:#1a1a3a,stroke:#9988ff,color:#fff

Foothold — Jenkins

Anonymous read on /people/api/json exposes usernames. Brute force gives Jenkins access. Groovy console reads credential files.

AD Credential Abuse

Service account passwords found in Jenkins workspace files. Kerberoastable SPNs provide offline cracking targets.

AD CS — ESC1

ApexVPN certificate template allows Subject Alternative Name in request. Any domain user can enroll a cert for any identity, including Domain Admin.

Exchange WriteDACL

Exchange Windows Permissions group holds WriteDACL on the domain object. Compromising MAILSERVER$ allows privilege escalation to Domain Admin.

OWA Password Spray

Outlook Web Access on port 443 is publicly reachable. The Global Address List exposes every user email after minimal access is obtained.

Hybrid Cloud Pivot

Password Hash Sync means AD credential compromise = cloud access. Compromised accounts work on Azure services and the custom portal.

Technical Guides

Follow the numbered pathway below to see the full setup progression, complete with actual screenshots, configuration commands, and detailed error logs from the build.

Errors & What Fixed Them

These are the errors that actually happened during the build, in the order they came up, and what fixed each one. Useful to read before starting a similar build.

Where Error Fix
Child DC join Weak local admin password rejected during DC promotion wizard net user administrator StrongPass123! before promoting
Linux domain join realm join failing — "insufficient permissions" — actually an RDNS lookup failure Add rdns = false under [libdefaults] in /etc/krb5.conf
Exchange install Installer freezes at 16% during file copy — CPU at 100% Disable Defender real-time: Set-MpPreference -DisableRealtimeMonitoring $true
Exchange install AutoReportProgress crash — CLI crashes mid-install Never click or scroll the installer window. Use a second PowerShell: Get-Content C:\ExchangeSetupLogs\ExchangeSetup.log -Tail 10 -Wait
Exchange forest prep /PrepareAllDomains fails — DomainNotReachableException on the torn-down child domain Use /PrepareDomain:hq.apex-corp.xyz instead
Exchange inbound mail External emails not arriving in OWA Set Receive Connector to AnonymousUsers, add Accepted Domain, update Email Address Policy
Exchange SSL Empty thumbprint error when running Get-ExchangeCertificate by Subject Filter by Issuer -like "*Let's Encrypt*" instead of Subject
Exchange outbound mail Outbound emails sitting in queue, never delivered Open a Vultr support ticket to unblock outbound port 25 — it is blocked by default on all VPS providers
Entra ID sync Synced users getting .onmicrosoft.com addresses instead of apex-corp.xyz Add Alternative UPN Suffix in AD Domains and Trusts, then bulk-update with Get-ADUser -Filter * | ForEach-Object { Set-ADUser -Identity $_ -UserPrincipalName "$($_.SamAccountName)@apex-corp.xyz" }
Jenkins install Wrong key URL — apt-get rejects the GPG key from pkg.jenkins.io Use jenkins.io-2026.key instead of jenkins.io.key in the curl command
Windows features Exchange prerequisite installer rejects Web-Asp-Net48 name Use the legacy name Web-Asp-Net45 — it installs .NET 4.8 on Server 2022, kept for backward compatibility