Master Pentesting Lab Creation with Vagrant & Docker
Build professional-grade testing environments using Infrastructure as Code. Learn to deploy, configure, and manage isolated lab networks for safe security practice.
Why Pentesting Labs Are Essential
In cybersecurity, hands-on practice is everything. Learn why professional penetration testers rely on controlled lab environments and how you can build your own.
Safe Practice Environment
Test attack techniques and defensive measures in isolated environments without risking production systems or violating laws. Practice ethical hacking in controlled settings.
Reproducible Setups
Infrastructure as Code ensures consistent lab environments that can be easily shared, versioned, and recreated. No more "works on my machine" problems.
Rapid Deployment
Quickly spin up, modify, and tear down complex multi-system environments for different testing scenarios. Focus on learning, not setup.
Skill Development
Practice reconnaissance, exploitation, and post-exploitation techniques in realistic scenarios that mirror real-world infrastructures.
Vagrant vs Docker: Choose Your Approach
Both technologies offer unique advantages for pentesting labs. Understanding their differences helps you choose the right tool for your specific needs.
Interactive Comparison Tool
Aspect | Vagrant + VirtualBox | Docker Compose |
---|---|---|
Isolation Level | Complete OS isolation | Process-level isolation |
Resource Usage | High (8GB+ RAM) | Low (4GB RAM) |
Startup Time | 2-5 minutes | 10-30 seconds |
OS Support | Multiple OS types | Linux only (natively) |
Kernel Testing | Full support | Limited/unsafe |
Learning Curve | Moderate | Moderate |
Scalability | Limited by hardware | Highly scalable |
Network Realism | Hardware-like networking | Software-defined networking |
Vagrant: Full Virtualization Power
Vagrant provides complete OS isolation through VirtualBox, making it ideal for testing kernel exploits, running multiple operating systems, and creating highly realistic network environments.
Vagrant Lab Simulator
Vagrant.configure("2") do |config| # Global settings config.vm.box = "ubuntu/focal64" config.vm.box_check_update = false # Web Server config.vm.define "webserver" do |web| web.vm.hostname = "webserver" web.vm.network "private_network", ip: "192.168.33.10" web.vm.network "forwarded_port", guest: 80, host: 8080, host_ip: "127.0.0.1" web.vm.provider "virtualbox" do |vb| vb.name = "PentestLab-Web" vb.memory = "2048" vb.cpus = 2 end web.vm.provision "shell", inline: <<-SHELL apt-get update -qq &> /dev/null apt-get install -y apache2 php libapache2-mod-php mysql-client &> /dev/null # Create vulnerable web app cat > /var/www/html/login.php << 'EOF' <?php // WARNING: This code is intentionally vulnerable for educational purposes. // Do NOT use in a production environment. if (isset(\$_POST['user']) && isset(\$_POST['pass'])) { \$user = \$_POST['user']; // No sanitization - SQL Injection vulnerability \$pass = \$_POST['pass']; // No sanitization // Example: Connect to a database (not fully implemented here for brevity) // \$conn = new mysqli("database_host", "db_user", "db_pass", "db_name"); // \$query = "SELECT * FROM users WHERE username='\$user' AND password='\$pass'"; // \$result = \$conn->query(\$query); echo "<p>Attempting login for user: " . htmlspecialchars(\$user) . "</p>"; echo "<p>Debug SQL Query (DO NOT SHOW IN PRODUCTION): SELECT * FROM users WHERE username='\$user' AND password='\$pass'</p>"; // if (\$result && \$result->num_rows > 0) { // echo "<p style='color:green;'>Login Successful (Simulated)</p>"; // } else { // echo "<p style='color:red;'>Login Failed (Simulated)</p>"; // } } ?> <!DOCTYPE html><html lang="en"><head><title>Login</title></head><body> <h2>Vulnerable Login Form</h2> <form method="post" action="login.php"> Username: <input name="user" type="text"><br> Password: <input name="pass" type="password"><br> <input type="submit" value="Login"> </form></body></html> EOF a2enmod php$(php -r 'echo PHP_MAJOR_VERSION.".".PHP_MINOR_VERSION;') # Enable correct PHP version systemctl restart apache2 systemctl enable apache2 SHELL end # Database Server config.vm.define "database" do |db| db.vm.hostname = "database" db.vm.network "private_network", ip: "192.168.33.11" db.vm.provider "virtualbox" do |vb| vb.name = "PentestLab-DB" vb.memory = "1024" vb.cpus = 1 end db.vm.provision "shell", inline: <<-SHELL apt-get update -qq &> /dev/null # Set frontend to noninteractive to avoid prompts export DEBIAN_FRONTEND=noninteractive apt-get install -y mysql-server &> /dev/null # Configure for remote access (intentionally insecure for lab) sed -i 's/bind-address.*/bind-address = 0.0.0.0/' /etc/mysql/mysql.conf.d/mysqld.cnf systemctl restart mysql # Create test database and user mysql -e "CREATE DATABASE IF NOT EXISTS testdb;" mysql -e "CREATE USER IF NOT EXISTS 'testuser'@'%' IDENTIFIED BY 'password123';" mysql -e "GRANT ALL ON testdb.* TO 'testuser'@'%';" mysql -e "FLUSH PRIVILEGES;" SHELL end # Target Server config.vm.define "target" do |target_vm| target_vm.vm.hostname = "target" target_vm.vm.network "private_network", ip: "192.168.33.12" target_vm.vm.provider "virtualbox" do |vb| vb.name = "PentestLab-Target" vb.memory = "512" vb.cpus = 1 end target_vm.vm.provision "shell", inline: <<-SHELL apt-get update -qq &> /dev/null apt-get install -y openssh-server vsftpd &> /dev/null # Weak SSH config for educational purposes sed -i 's/#PermitRootLogin prohibit-password/PermitRootLogin yes/' /etc/ssh/sshd_config sed -i 's/PasswordAuthentication no/PasswordAuthentication yes/' /etc/ssh/sshd_config echo 'root:toor' | chpasswd # Anonymous FTP access echo 'anonymous_enable=YES' >> /etc/vsftpd.conf systemctl restart sshd systemctl restart vsftpd SHELL end end
Complete OS Isolation
Each virtual machine runs its own kernel, providing maximum isolation for testing kernel exploits and malware analysis safely.
Multi-OS Support
Run Windows, Linux, and specialized security distributions like Kali Linux in the same lab environment.
Hardware Simulation
Virtual networking closely mimics physical hardware, perfect for learning real-world network penetration techniques.
Docker: Lightweight & Fast
Docker Compose offers rapid deployment and efficient resource usage, perfect for web application testing, microservices scenarios, and when you need to quickly iterate through different configurations.
Docker Lab Simulator
version: '3.8' services: webserver: image: ubuntu:22.04 container_name: pentestlab-web hostname: webserver networks: pentestlab_net: ipv4_address: 172.20.0.10 ports: - "127.0.0.1:8080:80" - "127.0.0.1:2222:22" volumes: - web_data:/var/www/html - ./scripts/web-setup.sh:/setup.sh environment: - DEBIAN_FRONTEND=noninteractive command: | bash -c " apt-get update -qq && \ apt-get install -y --no-install-recommends apache2 php libapache2-mod-php mysql-client openssh-server sudo && \ chmod +x /setup.sh && /setup.sh && \ echo 'root:toor' | chpasswd && \ sed -i 's/#PermitRootLogin prohibit-password/PermitRootLogin yes/' /etc/ssh/sshd_config && \ sed -i 's/PasswordAuthentication no/PasswordAuthentication yes/' /etc/ssh/sshd_config && \ service ssh start && \ apachectl -D FOREGROUND" depends_on: - database restart: unless-stopped database: image: mysql:8.0 container_name: pentestlab-db hostname: database networks: pentestlab_net: ipv4_address: 172.20.0.11 ports: - "127.0.0.1:3306:3306" environment: - MYSQL_ROOT_PASSWORD=rootpass - MYSQL_DATABASE=webapp - MYSQL_USER=webuser - MYSQL_PASSWORD=webpass123 volumes: - db_data:/var/lib/mysql - ./scripts/db-init.sql:/docker-entrypoint-initdb.d/init.sql restart: unless-stopped target: image: ubuntu:22.04 container_name: pentestlab-target hostname: target networks: pentestlab_net: ipv4_address: 172.20.0.12 ports: - "127.0.0.1:2223:22" - "127.0.0.1:8081:80" - "127.0.0.1:2121:21" volumes: - target_data:/var/www/html - ./scripts/target-setup.sh:/setup.sh environment: - DEBIAN_FRONTEND=noninteractive command: | bash -c " apt-get update -qq && \ apt-get install -y --no-install-recommends openssh-server vsftpd telnetd apache2 && \ chmod +x /setup.sh && /setup.sh && \ echo 'root:toor' | chpasswd && \ sed -i 's/#PermitRootLogin prohibit-password/PermitRootLogin yes/' /etc/ssh/sshd_config && \ sed -i 's/PasswordAuthentication no/PasswordAuthentication yes/' /etc/ssh/sshd_config && \ echo 'anonymous_enable=YES' >> /etc/vsftpd.conf && \ service ssh start && \ service vsftpd start && \ apachectl -D FOREGROUND" restart: unless-stopped networks: pentestlab_net: driver: bridge ipam: config: - subnet: 172.20.0.0/24 gateway: 172.20.0.1 volumes: web_data: db_data: target_data:
Lightning Fast
Containers start in seconds, not minutes. Perfect for rapid testing iterations and continuous integration workflows.
Resource Efficient
Run complex multi-service environments on modest hardware. Shared kernel architecture minimizes overhead.
Modern Architectures
Perfect for testing microservices, APIs, and cloud-native applications that reflect current enterprise environments.
Hands-On Practice Exercises
Apply your knowledge with structured exercises that guide you through real pentesting scenarios using your lab environment.
Exercise 1: Network Reconnaissance
Deploy your lab and perform comprehensive network discovery. Learn to use nmap for host discovery, port scanning, and service enumeration across your three-server setup.
Exercise 2: Web Application Testing
Test the intentionally vulnerable web application for SQL injection, directory traversal, and other OWASP Top 10 vulnerabilities using both manual and automated techniques.
Exercise 3: System Exploitation
Exploit weak SSH configurations, practice privilege escalation techniques, and learn lateral movement between systems in your isolated lab environment.
Exercise 4: Defense & Hardening
Switch perspectives and implement security controls, configure monitoring, and harden your lab systems to understand both offensive and defensive cybersecurity.
Exercise Details
Quick Deployment Guide
# 1. Ensure Vagrant and VirtualBox are installed # 2. Create project directory mkdir pentesting-lab-vagrant && cd pentesting-lab-vagrant # 3. Create Vagrantfile (copy content from "Vagrantfile (Ruby)" above) # Example: nano Vagrantfile # (Paste the Vagrantfile content here) # 4. Start the lab environment (this may take a few minutes) vagrant up # 5. Check status of all machines vagrant status # 6. Access individual machines via SSH # vagrant ssh webserver # vagrant ssh database # vagrant ssh target # 7. Access web application (if webserver is up): http://localhost:8080/login.php # 8. Stop the lab when done (preserves VMs) vagrant halt # 9. Completely remove the lab and VMs (frees disk space) vagrant destroy -f
# 1. Ensure Docker and Docker Compose are installed # 2. Create project directory mkdir pentesting-lab-docker && cd pentesting-lab-docker # 3. Create docker-compose.yml (copy content from "docker-compose.yml" above) # Example: nano docker-compose.yml # (Paste the docker-compose.yml content here) # 4. Create a 'scripts' directory for setup/init files if your compose file uses them # mkdir scripts # touch scripts/web-setup.sh scripts/db-init.sql scripts/target-setup.sh # (Populate these scripts as needed for your lab setup) # 5. Build and start containers in detached mode docker compose up -d --build # 6. Check status of all containers docker compose ps # 7. Access containers with interactive shell # docker exec -it pentestlab-web bash # docker exec -it pentestlab-db bash # (or mysql client: docker exec -it pentestlab-db mysql -u root -prootpass) # docker exec -it pentestlab-target bash # 8. Access web application (if webserver is up): http://localhost:8080 (or configured port) # 9. View container logs (e.g., for webserver) docker compose logs webserver # 10. Stop all containers (preserves volumes) docker compose down # 11. Remove everything including volumes (frees disk space) docker compose down -v