Penetration Testing Lab Setup

Build your own practice environments for penetration testing. From online platforms to home lab setups with vulnerable VMs and Active Directory networks.

Last Updated: March 2026

Lab Comparison at a Glance

Lab Type RAM Disk Setup Time Difficulty Cost
Kali Setup 4GB 80GB ~1 hr Beginner Free
Web App Lab 2GB 10GB ~15 min Beginner Free
Vulnerable VMs 4GB 40GB ~30 min Beginner Free
AD Lab 16GB+ 160GB ~2 hrs Intermediate Free
Malware Lab 8GB+ 100GB ~2 hrs Intermediate Free
Wireless Lab 4GB 20GB ~1 hr Intermediate $30-60
Purple Team / SIEM 32GB+ 200GB ~3 hrs Advanced Free
CI/CD Pipeline 8GB+ 50GB ~1 hr Advanced Free
Cloud Lab 4GB 20GB ~1 hr Advanced $$

Recommended Lab Network Layout

NAT Network — Internet Access

10.0.0.0/24 • VMs can reach the internet for updates & cloud tools

๐Ÿ‰

Kali (Attacker)

.100

โ˜๏ธ

Cloud Tools

.200

โš™๏ธ

CI/CD (Docker)

.201

๐ŸŒ

Web Lab (Docker)

.202

Kali bridges both networks via dual NICs

Host-Only / Internal Network — Isolated

10.10.10.0/24 • No internet • Attack targets & detection

๐Ÿ‰

Kali (2nd NIC)

.100

๐Ÿฐ

DC01 (AD Lab)

.10

๐Ÿ–ฅ๏ธ

WS01 (Joined)

.20

๐Ÿ›ก๏ธ

SIEM (Wazuh/ELK)

.50

Use dual NICs on Kali: NAT for internet/updates, Host-Only for isolated lab attacks. Never expose vulnerable VMs to your home network.

Recommended Learning Path

1. Kali Setup โ†’ 2. Web Lab / VMs โ†’ 3. AD Lab โ†’ 4. Malware Lab โ†’ 5. Cloud / CI/CD โ†’ 6. Purple Team

Start with your attack machine, practice on web apps, then progress to enterprise, cloud, and detection environments.

Online Learning Platforms

Hack The Box

Active machines to hack, both Windows and Linux. Pro Labs for enterprise environments.

  • โœ“ 200+ retired machines
  • โœ“ Active Directory labs
  • โœ“ Starting Point for beginners
  • โœ“ Academy for structured learning
hackthebox.com โ†’

TryHackMe

Beginner-friendly with guided rooms. Learning paths from basics to advanced.

  • โœ“ Guided walkthroughs
  • โœ“ Learning paths
  • โœ“ Browser-based AttackBox
  • โœ“ Great for beginners
tryhackme.com โ†’

PentesterLab

Web application security focused. Excellent for learning specific vulnerabilities.

  • โœ“ Web app focused
  • โœ“ Badge system progression
  • โœ“ Real-world scenarios
  • โœ“ API security labs
pentesterlab.com โ†’

PortSwigger Web Academy

Free web security training from Burp Suite creators.

portswigger.net โ†’

Proving Grounds

OffSec's practice platform. PG Play is free; PG Practice for OSCP prep.

offsec.com โ†’

HackMyVM

Free community-driven vulnerable VMs with flag submission and leaderboards.

hackmyvm.eu โ†’

Pwned Labs

Hands-on cloud security labs for AWS and Azure with guided scenarios.

pwnedlabs.io โ†’

CyberDefenders

Blue team/DFIR focused labs with real-world incident response challenges.

cyberdefenders.org โ†’

DVWA / bWAPP

Self-hosted vulnerable web apps for web exploitation practice.

DVWA GitHub โ†’

Building a Home Lab

Hardware Requirements

Minimum: 16GB RAM, SSD storage, quad-core CPU. Recommended: 32GB+ RAM, 500GB+ SSD. More RAM = more VMs running simultaneously.

Budget Lab Hardware

Refurbished enterprise mini PCs are the best value for home labs:

  • โ€ข Dell OptiPlex Micro/SFF โ€” i5/i7, upgradeable to 64GB RAM, under $150 refurbished
  • โ€ข HP EliteDesk 800 G5/G6 โ€” compact, reliable, easy RAM/SSD upgrades
  • โ€ข Lenovo ThinkCentre M series โ€” similar specs, often available on eBay/Amazon Renewed
  • โ€ข Add a 1TB NVMe SSD (~$60) and 32-64GB RAM (~$50-90) for a complete lab under $300

Virtualization Setup

Choose a hypervisor that suits your operating system and needs:

VMware Workstation Pro

Free for personal use (since May 2024). Best compatibility, snapshots, and networking.

Download

VirtualBox

Free & Open Source. Good for learning, cross-platform.

Download

Proxmox VE

Free bare-metal hypervisor. Runs VMs and containers, web UI, ideal for dedicated lab servers.

Download

Network Configuration

Proper network isolation is crucial. Configure your hypervisor with the following networks:

  • NAT Network: VMs can reach the internet but are isolated from your host LAN.
  • Host-Only Network: VMs communicate with each other and the host, but no internet.
  • Internal Network: Completely isolated VM-to-VM communication.

Kali Linux Attack Machine

Download the official VM image from kali.org. Once installed, run the following commands to set up your environment:

kali-setup.sh
bash
# Update system
sudo apt update && sudo apt upgrade -y

# Install additional tools
sudo apt install -y \
    gobuster feroxbuster \
    bloodhound neo4j \
    netexec evil-winrm \
    seclists \
    docker.io docker-compose-v2

# Enable services
sudo systemctl enable ssh
sudo systemctl start ssh
sudo systemctl enable postgresql
sudo systemctl start postgresql

# Initialize Metasploit database
sudo msfdb init

# Create directory structure
mkdir -p ~/engagements/client_name/{recon,scans,exploits,loot,notes}

# Clone useful repos
git clone https://github.com/danielmiessler/SecLists ~/tools/SecLists
git clone https://github.com/carlospolop/PEASS-ng ~/tools/PEASS-ng
git clone https://github.com/samratashok/nishang ~/tools/nishang

# Install Python tools via pipx (isolated environments)
pipx install impacket
pipx install netexec

# Start BloodHound CE
sudo neo4j console &
bloodhound

# Or use BloodHound Community Edition (Docker):
# curl -L https://ghst.ly/getbhce | docker compose -f - up
# Update system
sudo apt update && sudo apt upgrade -y

# Install additional tools
sudo apt install -y \
    gobuster feroxbuster \
    bloodhound neo4j \
    netexec evil-winrm \
    seclists \
    docker.io docker-compose-v2

# Enable services
sudo systemctl enable ssh
sudo systemctl start ssh
sudo systemctl enable postgresql
sudo systemctl start postgresql

# Initialize Metasploit database
sudo msfdb init

# Create directory structure
mkdir -p ~/engagements/client_name/{recon,scans,exploits,loot,notes}

# Clone useful repos
git clone https://github.com/danielmiessler/SecLists ~/tools/SecLists
git clone https://github.com/carlospolop/PEASS-ng ~/tools/PEASS-ng
git clone https://github.com/samratashok/nishang ~/tools/nishang

# Install Python tools via pipx (isolated environments)
pipx install impacket
pipx install netexec

# Start BloodHound CE
sudo neo4j console &
bloodhound

# Or use BloodHound Community Edition (Docker):
# curl -L https://ghst.ly/getbhce | docker compose -f - up

Recommended Vulnerable VMs

Linux VMs

  • Metasploitable 2/3

    Classic intentionally vulnerable VM

  • DVWA (Damn Vulnerable Web App)

    Web vulnerabilities - SQLi, XSS, etc.

  • bWAPP

    100+ web vulnerabilities

  • VulnHub Machines

    Kioptrix, Mr. Robot, Stapler

Windows VMs

  • Windows 10/11 Eval

    90-day evaluation licenses from Microsoft

  • Windows Server Eval

    180-day eval for AD labs

  • Yourcomputer (VulnHub)

    Vulnerable Windows machine

  • YOURCOMPANY

    HTB-style Windows targets

docker-labs.sh
bash
# Quick Vulnerable Web App Setup with Docker

# DVWA
docker run -d -p 80:80 vulnerables/web-dvwa
# Access at http://localhost
# Login: admin/password

# bWAPP
docker run -d -p 8080:80 raesene/bwapp
# Access at http://localhost:8080/install.php

# OWASP Juice Shop
docker run -d -p 3000:3000 bkimminich/juice-shop
# Access at http://localhost:3000

# WebGoat (OWASP)
docker run -d -p 8081:8080 -p 9090:9090 webgoat/webgoat
# Access at http://localhost:8081/WebGoat

# SQLi-labs
docker run -d -p 8082:80 acgpiano/sqli-labs
# Access at http://localhost:8082

# NodeGoat
docker run -d -p 4000:4000 owasp/nodegoat
# Access at http://localhost:4000

# Run multiple with docker compose
cat > docker-compose.yml << 'EOF'
services:
  dvwa:
    image: vulnerables/web-dvwa
    ports:
      - "80:80"
  juiceshop:
    image: bkimminich/juice-shop
    ports:
      - "3000:3000"
  webgoat:
    image: webgoat/webgoat
    ports:
      - "8080:8080"
      - "9090:9090"
EOF
docker compose up -d
# Quick Vulnerable Web App Setup with Docker

# DVWA
docker run -d -p 80:80 vulnerables/web-dvwa
# Access at http://localhost
# Login: admin/password

# bWAPP
docker run -d -p 8080:80 raesene/bwapp
# Access at http://localhost:8080/install.php

# OWASP Juice Shop
docker run -d -p 3000:3000 bkimminich/juice-shop
# Access at http://localhost:3000

# WebGoat (OWASP)
docker run -d -p 8081:8080 -p 9090:9090 webgoat/webgoat
# Access at http://localhost:8081/WebGoat

# SQLi-labs
docker run -d -p 8082:80 acgpiano/sqli-labs
# Access at http://localhost:8082

# NodeGoat
docker run -d -p 4000:4000 owasp/nodegoat
# Access at http://localhost:4000

# Run multiple with docker compose
cat > docker-compose.yml << 'EOF'
services:
  dvwa:
    image: vulnerables/web-dvwa
    ports:
      - "80:80"
  juiceshop:
    image: bkimminich/juice-shop
    ports:
      - "3000:3000"
  webgoat:
    image: webgoat/webgoat
    ports:
      - "8080:8080"
      - "9090:9090"
EOF
docker compose up -d

Active Directory Lab Setup

Lab Requirements

  • Domain Controller: Windows Server 2019/2022 (4GB RAM)
  • Workstations: 2x Windows 10/11 (2GB RAM each)
  • Attacker: Kali Linux (4GB RAM)
  • Total RAM: ~12GB minimum

Network Configuration

Use a static IP scheme on an isolated network:

  • DC01: 10.0.0.1
  • WS01: 10.0.0.10
  • WS02: 10.0.0.11
  • Kali: 10.0.0.100
ad-lab-setup.ps1
powershell
# ==========================================
# Step 1: Domain Controller Setup
# ==========================================

# Open PowerShell as Admin

# Set computer name
Rename-Computer -NewName DC01 -Restart

# Install AD DS role
Install-WindowsFeature -Name AD-Domain-Services -IncludeManagementTools

# Promote to Domain Controller
Install-ADDSForest -DomainName "lab.local" -DomainNetbiosName "LAB" -InstallDns

# After restart, create users and groups
Import-Module ActiveDirectory

# Create OUs
New-ADOrganizationalUnit -Name "Lab Users" -Path "DC=lab,DC=local"
New-ADOrganizationalUnit -Name "Lab Computers" -Path "DC=lab,DC=local"
New-ADOrganizationalUnit -Name "Lab Groups" -Path "DC=lab,DC=local"

# Create users with weak passwords (for testing)
$users = @(
    @&#123;Name="John Smith"; SamAccountName="jsmith"; Password="Password123!"&#125;,
    @&#123;Name="Jane Doe"; SamAccountName="jdoe"; Password="Summer2026!"&#125;,
    @&#123;Name="Admin User"; SamAccountName="admin.user"; Password="Admin@123"&#125;,
    @&#123;Name="Service Account"; SamAccountName="svc_sql"; Password="SQLService1!"&#125;
)

foreach ($user in $users) &#123;
    New-ADUser -Name $user.Name -SamAccountName $user.SamAccountName -UserPrincipalName "$($user.SamAccountName)@lab.local" -AccountPassword (ConvertTo-SecureString $user.Password -AsPlainText -Force) -Enabled $true -PasswordNeverExpires $true -Path "OU=Lab Users,DC=lab,DC=local"
&#125;

# Create groups
New-ADGroup -Name "IT Admins" -GroupScope Global -Path "OU=Lab Groups,DC=lab,DC=local"
New-ADGroup -Name "HR" -GroupScope Global -Path "OU=Lab Groups,DC=lab,DC=local"

# Add users to groups
Add-ADGroupMember -Identity "IT Admins" -Members "admin.user"
Add-ADGroupMember -Identity "Domain Admins" -Members "admin.user"

# ==========================================
# Step 2: Configure Vulnerabilities
# ==========================================

# Kerberoastable user (SPN)
setspn -a MSSQLSvc/dc01.lab.local:1433 svc_sql

# AS-REP Roastable user
Set-ADAccountControl -Identity jdoe -DoesNotRequirePreAuth $true

# SMB Signing disabled (via Registry for lab simplicity)
Set-ItemProperty -Path "HKLM:\System\CurrentControlSet\Services\LanmanServer\Parameters" -Name "requiresecuritysignature" -Value 0

# ==========================================
# Step 3: Join Workstations (Run on Workstation)
# ==========================================

# Set DNS to DC IP
Set-DnsClientServerAddress -InterfaceAlias "Ethernet0" -ServerAddresses "10.0.0.1"

# Join Domain
Add-Computer -DomainName "lab.local" -Restart
# ==========================================
# Step 1: Domain Controller Setup
# ==========================================

# Open PowerShell as Admin

# Set computer name
Rename-Computer -NewName DC01 -Restart

# Install AD DS role
Install-WindowsFeature -Name AD-Domain-Services -IncludeManagementTools

# Promote to Domain Controller
Install-ADDSForest -DomainName "lab.local" -DomainNetbiosName "LAB" -InstallDns

# After restart, create users and groups
Import-Module ActiveDirectory

# Create OUs
New-ADOrganizationalUnit -Name "Lab Users" -Path "DC=lab,DC=local"
New-ADOrganizationalUnit -Name "Lab Computers" -Path "DC=lab,DC=local"
New-ADOrganizationalUnit -Name "Lab Groups" -Path "DC=lab,DC=local"

# Create users with weak passwords (for testing)
$users = @(
    @&#123;Name="John Smith"; SamAccountName="jsmith"; Password="Password123!"&#125;,
    @&#123;Name="Jane Doe"; SamAccountName="jdoe"; Password="Summer2026!"&#125;,
    @&#123;Name="Admin User"; SamAccountName="admin.user"; Password="Admin@123"&#125;,
    @&#123;Name="Service Account"; SamAccountName="svc_sql"; Password="SQLService1!"&#125;
)

foreach ($user in $users) &#123;
    New-ADUser -Name $user.Name -SamAccountName $user.SamAccountName -UserPrincipalName "$($user.SamAccountName)@lab.local" -AccountPassword (ConvertTo-SecureString $user.Password -AsPlainText -Force) -Enabled $true -PasswordNeverExpires $true -Path "OU=Lab Users,DC=lab,DC=local"
&#125;

# Create groups
New-ADGroup -Name "IT Admins" -GroupScope Global -Path "OU=Lab Groups,DC=lab,DC=local"
New-ADGroup -Name "HR" -GroupScope Global -Path "OU=Lab Groups,DC=lab,DC=local"

# Add users to groups
Add-ADGroupMember -Identity "IT Admins" -Members "admin.user"
Add-ADGroupMember -Identity "Domain Admins" -Members "admin.user"

# ==========================================
# Step 2: Configure Vulnerabilities
# ==========================================

# Kerberoastable user (SPN)
setspn -a MSSQLSvc/dc01.lab.local:1433 svc_sql

# AS-REP Roastable user
Set-ADAccountControl -Identity jdoe -DoesNotRequirePreAuth $true

# SMB Signing disabled (via Registry for lab simplicity)
Set-ItemProperty -Path "HKLM:\System\CurrentControlSet\Services\LanmanServer\Parameters" -Name "requiresecuritysignature" -Value 0

# ==========================================
# Step 3: Join Workstations (Run on Workstation)
# ==========================================

# Set DNS to DC IP
Set-DnsClientServerAddress -InterfaceAlias "Ethernet0" -ServerAddresses "10.0.0.1"

# Join Domain
Add-Computer -DomainName "lab.local" -Restart

Automated Lab Deployment

GOAD (Game of AD)

Full AD lab with multiple forests, trusts, and vulnerabilities. Deploy with Vagrant.

GitHub: Orange-Cyberdefense/GOAD โ†’

Ludus

Automated lab platform by Badsector Labs. Deploy AD, Linux, and security tooling with Proxmox.

docs.ludus.cloud โ†’

GOAD Installation

Requires Vagrant and a provider (VirtualBox, VMware, etc.).

goad-deploy.sh
bash
# Clone GOAD repository
git clone https://github.com/Orange-Cyberdefense/GOAD.git
cd GOAD

# Install python dependencies
pip install ansible pywinrm

# Deploy with Vagrant (VirtualBox provider)
cd ad/GOAD/providers/virtualbox
vagrant up
# Clone GOAD repository
git clone https://github.com/Orange-Cyberdefense/GOAD.git
cd GOAD

# Install python dependencies
pip install ansible pywinrm

# Deploy with Vagrant (VirtualBox provider)
cd ad/GOAD/providers/virtualbox
vagrant up

Ludus Installation

ludus-deploy.sh
bash
# Ludus requires a dedicated Proxmox server
# Install via the official installer:
curl -s https://ludus.cloud/install | bash

# Configure your first range
ludus range config get > config.yml
# Edit config.yml to define your lab VMs
ludus range config set -f config.yml

# Deploy the range
ludus range deploy

# Check status
ludus range status
# Ludus requires a dedicated Proxmox server
# Install via the official installer:
curl -s https://ludus.cloud/install | bash

# Configure your first range
ludus range config get > config.yml
# Edit config.yml to define your lab VMs
ludus range config set -f config.yml

# Deploy the range
ludus range deploy

# Check status
ludus range status

Lab Best Practices

Always use isolated networks for vulnerable VMs. Take snapshots before testing so you can easily restore. Document your lab setup for reproducibility. Consider using Infrastructure as Code (Vagrant/Terraform) for easy rebuilds.

Lab Maintenance & Lifecycle

๐Ÿ“… Regular Maintenance

  • โ€ข Weekly: Update Kali tools (sudo apt update && sudo apt upgrade)
  • โ€ข Monthly: Snapshot VMs in clean state before major changes
  • โ€ข Quarterly: Rebuild from scratch to practice setup and avoid config drift
  • โ€ข After testing: Revert to clean snapshots โ€” don't let exploits persist

๐Ÿ’พ Snapshot Strategy

  • โ€ข Base Install: Clean OS with updates applied
  • โ€ข Configured: All tools installed, services running
  • โ€ข Vulnerable: Intentional misconfigs added (for labs)
  • โ€ข Pre-Engagement: Right before running specific attacks

Export & Share Lab Configs

Export your lab VMs as OVA files for backup, sharing with teammates, or rebuilding on different hardware.

bash
# VMware - Export from GUI:
# File > Export to OVF > Choose OVA format

# VirtualBox - Export from CLI:
VBoxManage export "Kali-Lab" -o kali-lab.ova
VBoxManage export "DC01" -o dc01-lab.ova
VBoxManage export "WS01" -o ws01-lab.ova

# Import on another machine:
VBoxManage import kali-lab.ova

# Compress for sharing (OVAs can be large):
# Windows
Compress-Archive -Path *.ova -DestinationPath lab-export.zip

# Linux
tar czf lab-export.tar.gz *.ova
# VMware - Export from GUI:
# File > Export to OVF > Choose OVA format

# VirtualBox - Export from CLI:
VBoxManage export "Kali-Lab" -o kali-lab.ova
VBoxManage export "DC01" -o dc01-lab.ova
VBoxManage export "WS01" -o ws01-lab.ova

# Import on another machine:
VBoxManage import kali-lab.ova

# Compress for sharing (OVAs can be large):
# Windows
Compress-Archive -Path *.ova -DestinationPath lab-export.zip

# Linux
tar czf lab-export.tar.gz *.ova

Infrastructure as Code Alternative

For repeatable setups, consider using Vagrant (VagrantFiles), Terraform (HCL), or Ansible (playbooks) instead of OVA exports. IaC configs are small, version-controllable, and rebuild identical environments from scratch. See the AD Lab page for GOAD and Ludus examples.