Project Zero: Enterprise Lab (Part 1)

case study

Build an Enterprise Network

last edited 2026-07-28

Designed and built a small enterprise lab network from scratch on a dedicated 10.0.0.0/24 NAT segment, provisioning Windows and Ubuntu servers and workstations, a MailHog mail server, a Wazuh security server, and a Kali attacker VM, all joined into the same environment as a realistic baseline for later attack simulation.

###Active Directory

In this section, I deployed a Windows Server domain controller that provides Active Directory Domain Services (AD DS), DNS, and DHCP to simulate a small enterprise network with centralized identity and network services.

1.Promote Windows Server to Domain Controller

This server is configured as the core of the lab environment, hosting AD DS, DNS, and DHCP on a dedicated internal network.

Domain controller after AD DS and management tools installation, ready to manage users, groups, and policies for the lab domain.
Domain controller after AD DS and management tools installation, ready to manage users, groups, and policies for the lab domain.

2.Configure Static IP on Domain Controller

I configured a static IP for the domain controller so that DNS, DHCP, and authentication are always reachable on the same address.

Static IP 10.0.0.5 assigned to the domain controller, with subnet 10.0.0.0/24 and default gateway 10.0.0.1 to ensure stable connectivity and routing.
Static IP 10.0.0.5 assigned to the domain controller, with subnet 10.0.0.0/24 and default gateway 10.0.0.1 to ensure stable connectivity and routing.

3.DNS Configuration

DNS runs on the domain controller to provide reliable name resolution for domain joins and internal services.

DNS configured on the domain controller to resolve internal lab.local records, with 10.0.0.5 pointing to itself for local names and 8.8.8.8 as a forwarder for external internet queries.
DNS configured on the domain controller to resolve internal lab.local records, with 10.0.0.5 pointing to itself for local names and 8.8.8.8 as a forwarder for external internet queries.

4.DHCP Scope

I created a DHCP scope that matches the internal subnet and reserves space for infrastructure hosts. Scope options ensure clients receive the correct gateway and DNS settings without manual configuration.

Screenshot from project documentation
IPv4 DHCP scope created for 10.0.0.0/24, defining the usable IP range for clients while reserving static addresses for core services like the gateway and domain controller.
IPv4 DHCP scope created for 10.0.0.0/24, defining the usable IP range for clients while reserving static addresses for core services like the gateway and domain controller.
DHCP scope options specifying default gateway 10.0.0.1 and DNS server 10.0.0.5 so new clients can immediately reach the domain controller and route traffic out of the subnet.
DHCP scope options specifying default gateway 10.0.0.1 and DNS server 10.0.0.5 so new clients can immediately reach the domain controller and route traffic out of the subnet.

With AD DS, DNS, and DHCP configured, any properly configured workstation on the 10.0.0.0/24 subnet can now join the corp.project-zero-dc.com domain and authenticate against the domain controller.

5.Add Users

I created multiple user accounts to simulate real employees and to test authentication, authorization, and future detection use cases.

User objects created in Active Directory Users and Computers to represent lab employees, enabling realistic sign‑ins, group membership testing, and permission scenarios.
User objects created in Active Directory Users and Computers to represent lab employees, enabling realistic sign‑ins, group membership testing, and permission scenarios.

Why this matters: This Active Directory core services setup gives me a realistic identity and network foundation to build on. It allows me to practice domain joins, centralized user management, and future security scenarios such as Group Policy hardening, log collection, and detection engineering for common AD attack paths.


##Windows Client - Join Domain

In this section, I provisioned a Windows 11 Enterprise workstation and joined to the Active Directory domain so I can simulate a real corporate user endpoint for authentication and future detection scenarios.

1.Configure Static Network Settings

I configured a static IP on the Windows client so it can reliably communicate with the lab gateway and domain controller.

Windows 11 client configured with static IP 10.0.0.100, gateway 10.0.0.1, and DNS 10.0.0.5, ensuring consistent connectivity to the domain controller.
Windows 11 client configured with static IP 10.0.0.100, gateway 10.0.0.1, and DNS 10.0.0.5, ensuring consistent connectivity to the domain controller.

2.Join the Active Directory Domain

Next, I pointed the workstation at the lab domain and joined it to Active Directory using a domain account.

Windows 11 workstation  project-zero-win-client  joining the  corp.project-zero-dc.com  domain using a domain user account.
Windows 11 workstation project-zero-win-client joining the corp.project-zero-dc.com domain using a domain user account.

3.Verify Successful Domain Enrollment

After the reboot, I verified that the machine was properly joined to the domain and could log in with an AD user.

Successful domain join confirmation for  project-zero-win-client , enabling users like John Doe to authenticate against the domain controller.
Successful domain join confirmation for project-zero-win-client, enabling users like John Doe to authenticate against the domain controller.

Why this matters:

This domain‑joined Windows client behaves like a real corporate workstation, interacting with the domain controller for logons and policy updates. It provides realistic endpoint activity that I can later monitor and correlate with server‑side events.


###Provision & Setup Ubuntu Desktop

In this section, I provisioned an Ubuntu 22.04 desktop and integrated it into the same lab network and Active Directory domain as the Windows hosts. This gives me a Linux endpoint that can authenticate against AD and behave like a real mixed‑OS enterprise environment.

1.Install Ubuntu Desktop

installed Ubuntu 22.04 Desktop and completed the initial setup wizard using default options for disk layout and updates.

Ubuntu Desktop 22.04 successfully installed and ready for configuration as a domain‑joined Linux workstation.
Ubuntu Desktop 22.04 successfully installed and ready for configuration as a domain‑joined Linux workstation.

2.Configure Network Settings

I configured a dedicated “Linux AD” network profile so the Ubuntu VM uses the same internal subnet as the rest of the lab and points DNS at the domain controller.

Ubuntu desktop configured with a static IP on the 10.0.0.0/24 subnet and DNS set to the Windows domain controller, ensuring reliable connectivity for domain lookups and authentication.
Ubuntu desktop configured with a static IP on the 10.0.0.0/24 subnet and DNS set to the Windows domain controller, ensuring reliable connectivity for domain lookups and authentication.

3.Install Active Directory Integration Packages

I used Samba and Winbind to integrate Ubuntu with Active Directory. Samba provides the AD domain membership and file‑sharing components, while Winbind lets the Linux system look up AD users and groups and authenticate them for logins, giving me centralized identity management for Linux using the same domain controller as my Windows hosts. Open a new terminal session. Update the system with:

sudo apt update

Install the necessary packages:

sudo apt -y install winbind libpam-winbind libnss-winbind krb5-config samba-dsdb-modules samba-vfs-modules

Screenshot from project documentation

4.Configure Samba for Active Directory

Move the smb.conf file to smb.conf.org. - We are doing this to replace the contents of smb.conf with our configurations instead.

sudo mv /etc/samba/smb.conf /etc/samba/smb.conf.org

Create and open the smb.conf file with Nano.

sudo nano /etc/samba/smb.conf

Replace realm and workgroup with the following:

plain text
	[global]
   kerberos method = secrets and keytab
   realm = CORP.PROJECT-ZERO-DC.COM
   workgroup = CORP
   security = ads
   template shell = /bin/bash
   winbind enum groups = Yes
   winbind enum users = Yes
   winbind separator = +
   idmap config * : rangesize = 1000000
   idmap config * : range = 1000000-19999999
   idmap config * : backend = autorid

5.Configure Name Service Switch (NSS)

Confirm passwd and group blocks have winbind set as a value. Add the winbind value if needed.

sudo nano /etc/nsswitch.conf

Screenshot from project documentation

6.Configure PAM Home Directory Creation

Every user who signs in interactively to Ubuntu needs a home directory. For domain users, this must be configured in advance so they can log in successfully and start using the system.

sudo pam-auth-update

7.Configure Domain Name Resolution

Change DNS settings to refer to AD.

sudo nano /etc/resolv.conf

Screenshot from project documentation

8.Join Ubuntu to Active Directory

Join the domain with Administrator:

sudo net ads join -U Administrator

Restart winbind:

systemctl restart winbind

Get Active Directory services information listing.

net ads info

List all available users

wbinfo -u

Login as CORP+janed:

sudo login

Screenshot from project documentation

9.Verify Domain Membership

Going back to the Server Manager, we should see LINUX-CLIENT under the “Computers” folder.

Successful interactive login on Ubuntu using an Active Directory user account on the  linux-client workstation, confirming that Linux authentication is now centrally managed through the same domain controller as the Windows clients.
Successful interactive login on Ubuntu using an Active Directory user account on the linux-clientworkstation, confirming that Linux authentication is now centrally managed through the same domain controller as the Windows clients.

Why this matters:

Having a domain‑joined Ubuntu desktop in the lab lets me simulate a realistic mixed‑platform environment where both Windows and Linux endpoints rely on the same identity infrastructure. This is useful for practicing cross‑platform authentication, access control, and later monitoring Linux activity alongside Windows events in my logging stack.


###Provision & Setup CORP-SVR

In this section, I provisioned a dedicated Ubuntu 22.04 “corporate server” (project-zero-corp-svr) that acts as a jumpbox into the internal lab network. From this server I will later host and manage internal services such as FTP, DNS, and email using Docker containers.

1.Configure network and DNS on CORP‑SVR

I cloned the existing Linux client VM to create project-zero-corp-svr, then updated its network configuration so it uses a fixed IP on the internal subnet and points DNS to the Windows domain controller.

Corporate server  corp-svr  configured with static IP 10.0.0.8, gateway 10.0.0.1, and DNS 10.0.0.5, placing it on the same internal 10.0.0.0/24 network as the rest of the lab.
Corporate server corp-svr configured with static IP 10.0.0.8, gateway 10.0.0.1, and DNS 10.0.0.5, placing it on the same internal 10.0.0.0/24 network as the rest of the lab.

2.Verify connectivity and join Active Directory

Text near ping + net ad join terminal screenshot:

Before joining the domain, I verified that corp-svr could reach the domain controller over the network and resolve the AD DNS name. I then used Samba/Winbind to join the CORP Active Directory domain under the built‑in Administrator account.

Network tests from  corp-svr  confirm successful connectivity and name resolution to  corp.project-zero-dc.com
Network tests from corp-svr confirm successful connectivity and name resolution to corp.project-zero-dc.com
Joined the  corp-svr  to the CORP domain using the AD Administrator account.
Joined the corp-svr to the CORP domain using the AD Administrator account.

3.Confirm CORP-SVR in Active Directory

After the join, I verified on the domain controller that the new CORP-SRV object was created correctly under the Computers container.

Active Directory Users and Computers view showing the  CORP-SVR computer object alongside other lab machines, confirming that the corporate server is now managed by the same domain controller as the Windows and Linux clients.
Active Directory Users and Computers view showing the CORP-SVRcomputer object alongside other lab machines, confirming that the corporate server is now managed by the same domain controller as the Windows and Linux clients.

4.Install Docker Engine on CORP-SVR

To host multiple internal services efficiently, I installed Docker Engine on corp-svrusing the official Docker apt repository for Ubuntu. This enables me to run isolated containers for services like FTP, DNS, and mail on a single Linux host. https://docs.docker.com/engine/install/ubuntu/

Docker Engine installed on  corp-svr  via the official Docker apt repository, preparing the server to run internal lab services as lightweight containers instead of separate VMs.
Docker Engine installed on corp-svr via the official Docker apt repository, preparing the server to run internal lab services as lightweight containers instead of separate VMs.

Why this matters:

This corporate server acts as a hardened jumpbox into the internal environment and a container host for key lab services. It mirrors how real organizations centralize access and backend services, and it gives me a flexible place to deploy and later monitor multiple internal applications from a single, domain‑joined Linux server.


### Email Server - MailHog

In this section, I deployed MailHog as an internal SMTP server to simulate email delivery without sending messages to external mail systems. This provides a safe environment for testing phishing campaigns, email-based attack scenarios, and security detections while allowing every message to be captured and inspected through the MailHog web interface.

1.Configure MailHog

I deployed MailHog using Docker Compose, exposing SMTP on port 1025 and the web interface on port 8025. This allows internal systems to send emails to MailHog while providing a browser based interface to inspect captured messages.

powershell
version: "3"
services:
  mailhog:
    image: mailhog/mailhog
    container_name: mailhog
    ports:
      - "1025:1025"
      - "8025:8025"

2.Create An Email Poller Script

To simulate a user actively receiving email, I created a Bash polling script that continuously queries the MailHog API for new messages addressed to janed. The script tracks previously processed messages, displays newly received emails in real time, and serves as a lightweight email client for later phishing demonstrations.

powershell
#!/bin/bash

MAILHOG_IP="10.0.0.8"  
TO_EMAIL="janed"
POLL_INTERVAL=30  # seconds

echo "📡 Janed's Mail Watcher started... polling every $POLL_INTERVAL seconds"
echo "🔎 Watching for new mail sent to: $TO_EMAIL@"

# Keep track of seen message IDs
SEEN_IDS_FILE="/tmp/mailhog_seen_ids_janed.txt"
touch "$SEEN_IDS_FILE"

while true; do
  # Fetch current message list
  curl -s http://$MAILHOG_IP:8025/api/v2/messages | jq -c '.items[]' | while read -r msg; do
    TO=$(echo "$msg" | jq -r '.To[].Mailbox')
    ID=$(echo "$msg" | jq -r '.ID')

    if [[ "$TO" == "$TO_EMAIL" && ! $(grep -Fx "$ID" "$SEEN_IDS_FILE") ]]; then
      SUBJECT=$(echo "$msg" | jq -r '.Content.Headers.Subject[0]')
      BODY=$(echo "$msg" | jq -r '.Content.Body')

      echo -e "\n📬 New Email Received!"
      echo "Subject: $SUBJECT"
      echo "From: $(echo "$msg" | jq -r '.Content.Headers.From[0]')"
      echo "Date: $(echo "$msg" | jq -r '.Created')"
      echo -e "Message:\n$BODY"
      echo "-----------------------------------"

      echo "$ID" >> "$SEEN_IDS_FILE"
    fi
  done

  sleep "$POLL_INTERVAL"
done

3.Poller starts

Email poller starts successfully and begins checking MailHog for new messages every 30 seconds.
Email poller starts successfully and begins checking MailHog for new messages every 30 seconds.

4.Send test email

Test email generated from   corp-svr   using a Python script to simulate internal email delivery.
Test email generated from corp-svr using a Python script to simulate internal email delivery.

5.Poller receives email

The polling script detects the new message immediately and displays the sender, subject, timestamp, and body retrieved from the MailHog API.
The polling script detects the new message immediately and displays the sender, subject, timestamp, and body retrieved from the MailHog API.

6.MailHog Web UI

MailHog web interface confirming successful delivery of the test email and storing it for inspection.
MailHog web interface confirming successful delivery of the test email and storing it for inspection.

###Security Server - Provision & Setup Ubuntu

In this section, I provisioned a dedicated Ubuntu security server (sec-box) on the internal lab subnet and integrated it with Active Directory so it can run security and monitoring tooling against the domain.

1.Configure network on sec-box

I updated the cloned VM’s network settings so the new security server uses a unique static IP on the internal subnet and points DNS at the domain controller.

Security server  sec-box  configured with static IP 10.0.0.10, gateway 10.0.0.1, and DNS 10.0.0.5, placing it on the same 10.0.0.0/24 lab network as the other hosts.
Security server sec-box configured with static IP 10.0.0.10, gateway 10.0.0.1, and DNS 10.0.0.5, placing it on the same 10.0.0.0/24 lab network as the other hosts.

2.Verify connectivity to the domain controller

I first verified that sec-box could reach the domain controller over both IP and DNS.

Connectivity checks from  sec-user@sec-box  to 10.0.0.5 and  corp.project-zero-dc.com , confirming that the security server can reach core AD services on the internal network.
Connectivity checks from sec-user@sec-box to 10.0.0.5 and corp.project-zero-dc.com, confirming that the security server can reach core AD services on the internal network.

3.Create a security operations account in Active Directory

On the domain controller, I created a dedicated secuser account in Active Directory to represent security operations when accessing domain resources from sec-box

secuser  account created in Active Directory under the Users container, providing a dedicated identity for security operations across the domain.
secuser account created in Active Directory under the Users container, providing a dedicated identity for security operations across the domain.

I tuned the secuser account properties and group membership so it remains usable for ongoing lab work and has sufficient rights to perform security administration tasks.

secuser  account options configured to avoid forced password changes or expiry during extended lab use.
secuser account options configured to avoid forced password changes or expiry during extended lab use.
secuser  initially assigned to  Domain Users , granting standard user access across the environment.
secuser initially assigned to Domain Users, granting standard user access across the environment.
secuser  added to  Domain Admins  for this lab, giving the security server administrative privileges needed to deploy and manage security tooling across the domain.
secuser added to Domain Admins for this lab, giving the security server administrative privileges needed to deploy and manage security tooling across the domain.

4.Join sec-box to domain

With networking and identity in place, I joined sec-box to the corp.project-zero-dc.com domain using Samba/Winbind.

sec-box  successfully joined to the  corp.project-zero-dc.com  domain using CORP\Administrator, enabling central management and domain authentication for the security server.
sec-box successfully joined to the corp.project-zero-dc.com domain using CORP\Administrator, enabling central management and domain authentication for the security server.
Restarted winbind.
Restarted winbind.

Why this matters:

This security server gives me an isolated, domain‑joined Linux host for running security and monitoring tools, mirroring how SOC teams operate from a dedicated bastion while still using centralized AD identities.


###Setup Wazuh

In this section I deploy Wazuh as the central SIEM/XDR for the lab. A dedicated Ubuntu security server (project-zero-sec-box) hosts the Wazuh stack, running the indexer, server, and dashboard. Lab endpoints used with Wazuh:

-AD Server – Windows Server 2025 (project-zero-dc)

Domain controller providing Active Directory, DNS, and DHCP for the lab.

-Windows 11 Enterprise Client (project-zero-win-client)

Domain-joined workstation used as the primary user endpoint.

-Ubuntu Desktop 22.04 Client (project-zero-linux-client)

Linux workstation representing a cross‑platform corporate client.

1.Installing Wazuh

I installed Wazuh on the project-zero-sec-box security server, which runs Ubuntu 22.04, using the official all‑in‑one installer script. By running:

curl -sO https://packages.wazuh.com/4.9/wazuh-install.sh && sudo bash ./wazuh-install.sh -a -i

After the installation completed, I verified that the Wazuh dashboard was reachable over HTTPS from my admin workstation. Accessing the web UI confirms that the core services are running and provides a central point to manage agents, rules, and alerts for the entire lab.

Browser warning for the self‑signed HTTPS certificate presented by the Wazuh dashboard.
Browser warning for the self‑signed HTTPS certificate presented by the Wazuh dashboard.
Wazuh web login page for the security server hosting the SIEM/XDR stack.
Wazuh web login page for the security server hosting the SIEM/XDR stack.

2.Deploying Agent on Windows Client project-zero-win-client

Once logged in, I used the navigation menu to open the Endpoint Summary under server management. This section provides an overview of all registered agents, their status, and their operating systems, and is where I verify that new agents have successfully connected.

Using the Wazuh menu to open the Endpoint Summary view for connected agents.
Using the Wazuh menu to open the Endpoint Summary view for connected agents.
Opening an elevated PowerShell session on the Windows 11 workstation to prepare for agent installation.
Opening an elevated PowerShell session on the Windows 11 workstation to prepare for agent installation.
User Account Control prompt confirming elevation of PowerShell prior to running the Wazuh agent command.
User Account Control prompt confirming elevation of PowerShell prior to running the Wazuh agent command.
Executing the Wazuh agent installation command and starting the service on  project-zero-win-client .
Executing the Wazuh agent installation command and starting the service on project-zero-win-client.

3.Endpoint summary showing the Windows Client in Wazuh

Back in the Wazuh dashboard, the Endpoint Summary updated to show project-zero-win-clientas an active Windows agent. This confirmed that the installation, enrollment, and connectivity between the workstation and the security server were working as expected.

Wazuh Endpoint Summary confirming the  project-zero-win-client  workstation is connected and active.
Wazuh Endpoint Summary confirming the project-zero-win-client workstation is connected and active.

4.Deploying agent on Linux Client project-zero-linux-client

Next, I deployed the agent on the Ubuntu desktop client. Once project-zero-linux-clientconnected, the endpoint summary reflected both Windows and Linux workstations, confirming cross‑platform coverage at the endpoint layer.

Screenshot from project documentation
Screenshot from project documentation

sudo wget https://packages.wazuh.com/4.x/apt/pool/main/w/wazuhagent/wazuh-agent_4.9.2-1_amd64.deb && sudo WAZUH_MANAGER='10.0.0.10' WAZUH_AGENT_GROUP='default' WAZUH_AGENT_NAME='project-zero-linux-client' dpkg -i ./wazuhagent_4.9.2-1_amd64.deb

systemctl commands:

sudo systemctl daemon-reload

sudo systemctl enable wazuh-agent

sudo systemctl start wazuh-agent

Wazuh endpoints view after adding the  project-zero-linux-client  Ubuntu workstation alongside the Windows client.
Wazuh endpoints view after adding the project-zero-linux-client Ubuntu workstation alongside the Windows client.

5.Deploying agent on Domain Controller project-zero-dc

Repeated the above steps from the Windows Client.

Powershell command:

powershell
Invoke-WebRequest -Uri
https://packages.wazuh.com/4.x/windows/wazuh-agent-4.9.2-1.msi -
OutFile $env:tmp\wazuh-agent; msiexec.exe /i $env:tmp\wazuh-agent
/q WAZUH_MANAGER='10.0.0.10' WAZUH_AGENT_GROUP='default'
WAZUH_AGENT_NAME='project-zero-dc'
All three key endpoints— project-zero-win-client ,  project-zero-linux-client , and  project-zero-dc - registered as active agents in Wazuh.
All three key endpoints—project-zero-win-client, project-zero-linux-client, and project-zero-dc- registered as active agents in Wazuh.

6.Centralized Agent configuration with agent.conf

After all three agents were deployed and connected, I organized the endpoints into OS specific groups in Wazuh.

project-zero-win-client and project-zero-dc are placed in the Windows group, and project-zero-linux-client is placed in the Linux group.

Grouping agents this way lets me manage log collection and detection rules centrally per group instead of configuring each host individually.

Editing the  project-zero-win-client  agent to place it in the Windows group.
Editing the project-zero-win-client agent to place it in the Windows group.
Editing the  project-zero-linux-client  agent to place it in the Linux group.
Editing the project-zero-linux-client agent to place it in the Linux group.
Editing the  project-zero-dc  agent to place it in the Windows group.
Editing the project-zero-dc agent to place it in the Windows group.

After grouping the agents, I used the Wazuh dashboard to define group‑level agent.conf policies for Windows and Linux.

The Windows group configuration tells agents on project-zero-dc and project-zero-win-client to forward the Security and Application event channels, while the Linux group configuration instructs project-zero-linux-client to send auth, secure, and audit logs.

Edit agent.conf
Edit agent.conf
Windows group  agent.conf  configured to forward both the Security and Application event channels from all Windows agents.
Windows group agent.conf configured to forward both the Security and Application event channels from all Windows agents.
Linux group  agent.conf  collecting  /var/log/auth.log ,  /var/log/secure , and  /var/log/audit/audit.log  from the Ubuntu workstation.
Linux group agent.conf collecting /var/log/auth.log, /var/log/secure, and /var/log/audit/audit.log from the Ubuntu workstation.

Why this matters:

By deploying Wazuh on a dedicated security server and onboarding the domain controller, Windows 11 client, and Ubuntu client, I created a centralized SIEM view of the entire lab.

Using agent groups and shared agent.confconfigurations, I standardize which Windows Event Logs and Linux log files are collected, avoiding per‑host configuration drift and making changes easy to manage at scale.This gives me the visibility I need to monitor authentication, endpoint activity, and privileged operations across the lab when I later run the full attack chain.