Build a Safe Practice Lab

Cyber Security · Lesson 4 of 31 8 min read Updated

You cannot learn security only by reading. You need systems to scan, break and fix. But you must never practise on systems you do not own. The answer is a lab: a small, private network of virtual machines on your own computer, where every target belongs to you.

In this lesson you will plan and build that lab: a hypervisor, an attacker machine running Kali Linux, deliberately vulnerable practice apps, and an isolated network that keeps everything away from the internet and from other people's devices.

What a lab is made of

A virtual machine (VM) is a complete computer running as a program inside your real computer (the host). A hypervisor is the software that runs VMs. Your lab needs:

PartSuggested choiceWhy
HypervisorOracle VirtualBox, or VMware Workstation ProBoth are free to download for personal use and run on Windows and Linux
Attacker VMKali LinuxA Debian-based distribution with hundreds of security tools preinstalled
Target VMUbuntu Server running practice apps in DockerA normal server you can harden and attack again and again
Practice appsOWASP Juice Shop, DVWADeliberately vulnerable web apps made for learning
NetworkHost-only or internal networkKeeps vulnerable machines away from the internet and your home Wi-Fi

A host with 8 GB of RAM can run two small VMs; 16 GB is more comfortable. Make sure hardware virtualisation (Intel VT-x or AMD-V) is turned on in your BIOS or UEFI settings.

Choosing the right network mode

Hypervisors offer several network modes. Choosing the wrong one is the most common lab mistake.

ModeWho can reach the VMUse in the lab
NATThe VM can reach the internet; nothing outside can reach itFine for downloading updates, then switch
BridgedThe VM joins your real network like a separate deviceAvoid for vulnerable VMs
Host-onlyOnly the host and other VMs on the same host-only networkBest for most labs
Internal networkOnly other VMs on that internal network, not even the hostMost isolated

In VirtualBox, the default host-only network is 192.168.56.0/24. The host is usually 192.168.56.1, and the built-in DHCP server hands out addresses from 192.168.56.101 upwards. In this course the examples assume the target VM is 192.168.56.101 and Kali is 192.168.56.102. Your addresses may differ, so always check.

On a Windows host you can list host-only adapters from PowerShell or Command Prompt. The path is the usual install folder:

PowerShell
& "C:\Program Files\Oracle\VirtualBox\VBoxManage.exe" list hostonlyifs

Give each VM two adapters while you set it up: adapter 1 on NAT for updates, adapter 2 on host-only for the lab. Once a target VM is fully set up, disable its NAT adapter so it has no internet at all.

Setting up the attacker and target

  1. Download a ready-made Kali VM image for VirtualBox or VMware from the official Kali website, and import it. The pre-built images log in as kali with password kali; change it at once with passwd.
  2. Install Ubuntu Server as the target VM and install Docker from Ubuntu's or Docker's official instructions.
  3. Update both VMs before you start (sudo apt update && sudo apt full-upgrade).
  4. Take a snapshot of each VM in its clean state. A snapshot saves the whole machine so you can return to it in seconds after you break something.

Inside the target VM, start Juice Shop. Notice the address before the ports: it publishes the app only on the host-only interface, not on every network the VM can see.

Terminal
# on the target VM (192.168.56.101)
sudo docker pull bkimminich/juice-shop
sudo docker run --rm -d --name juice -p 192.168.56.101:3000:3000 bkimminich/juice-shop

For DVWA, clone the official repository and follow its README, which uses Docker Compose (docker compose up -d) and serves the app on port 4280. The default DVWA login is admin / password, and DVWA has four security levels (low, medium, high and impossible) so you can compare weak code with secure code.

From Kali, confirm you can reach the target and nothing else:

Terminal
ip -brief address
ping -c 3 192.168.56.101
curl -I http://192.168.56.101:3000
Output
lo               UNKNOWN        127.0.0.1/8 ::1/128
eth1             UP             192.168.56.102/24 fe80::a00:27ff:fe8e:1c2d/64

The ip -brief address output above is an example; your interface names and addresses may differ. ping should get replies and curl -I should print an HTTP/1.1 200 OK header from Juice Shop.

Checking addresses before you touch them

Every address you test must be a private lab address. IP ranges such as 10.0.0.0/8, 172.16.0.0/12 and 192.168.0.0/16 are reserved for private networks and are never routed on the internet. Python's ipaddress module can check this for you, and it is a good habit to build into every script:

PythonRun it yourself
import ipaddress

LAB = ipaddress.ip_network("192.168.56.0/24")

for text in ["192.168.56.101", "192.168.1.20", "142.250.183.14", "10.0.2.15"]:
    ip = ipaddress.ip_address(text)
    if ip in LAB:
        verdict = "lab target, OK to test"
    elif ip.is_private:
        verdict = "private but NOT the lab (home or NAT network)"
    else:
        verdict = "PUBLIC internet address, never test"
    print(f"{text:<16} {verdict}")
Output
192.168.56.101   lab target, OK to test
192.168.1.20     private but NOT the lab (home or NAT network)
142.250.183.14   PUBLIC internet address, never test
10.0.2.15        private but NOT the lab (home or NAT network)

10.0.2.15 is the address VirtualBox usually gives a VM on its NAT adapter, so it is private but still not a lab target.

Keeping a lab inventory

Write down what is in your lab. When you return after a week, you will not remember which VM had which app or which snapshot was clean.

PythonRun it yourself
lab = [
    {"name": "kali", "ip": "192.168.56.102", "role": "attacker", "snapshot": "clean-2026-11-01"},
    {"name": "target", "ip": "192.168.56.101", "role": "Juice Shop :3000, DVWA :4280", "snapshot": "clean-2026-11-01"},
    {"name": "win-test", "ip": "192.168.56.103", "role": "Windows logging practice", "snapshot": ""},
]

for vm in lab:
    status = vm["snapshot"] or "NO SNAPSHOT, take one first"
    print(f'{vm["name"]:<9}{vm["ip"]:<16}{vm["role"]:<30}{status}')
Output
kali     192.168.56.102  attacker                      clean-2026-11-01
target   192.168.56.101  Juice Shop :3000, DVWA :4280  clean-2026-11-01
win-test 192.168.56.103  Windows logging practice      NO SNAPSHOT, take one first

Lab safety rules

  • Only test machines and apps listed in your lab inventory.
  • Keep vulnerable VMs on host-only or internal networks, with no NAT adapter once set up.
  • Publish Docker ports on the lab address only (as in -p 192.168.56.101:3000:3000), never on all interfaces.
  • Never reuse a real password inside the lab.
  • Keep your host operating system and hypervisor updated, since the host is the one machine that touches both worlds.
  • Revert to a clean snapshot after each exercise.

Common mistakes

  • Using bridged mode for a vulnerable VM. Everyone on your Wi-Fi can now attack it, and your scans may hit other people's devices.
  • Publishing a Docker port as -p 3000:3000 on a laptop. That listens on every interface, including public Wi-Fi at a cafe. Bind to a specific lab address.
  • Skipping snapshots. Without them, one broken configuration can cost you hours of reinstalling.
  • Practising on a "free hosting" site or a friend's website. That is not a lab. Only targets you own and control are safe.

Key points

  • A lab is a private network of VMs that you own, so practice is legal and safe.
  • Use VirtualBox or VMware, a Kali Linux attacker VM and a target VM running Juice Shop and DVWA.
  • Host-only or internal networks isolate the lab; avoid bridged mode for vulnerable machines.
  • VirtualBox's default host-only network is 192.168.56.0/24.
  • Take snapshots of clean VMs and revert after each exercise.
  • Check every target address is in your lab range before you test it.

Exercise

Write a Python function safe_target(address) that returns True only for addresses inside 192.168.56.0/24, excluding the host address 192.168.56.1. Test it with at least four addresses, including a public one and the host address.

Show solution
Python
import ipaddress

LAB = ipaddress.ip_network("192.168.56.0/24")
HOST = ipaddress.ip_address("192.168.56.1")

def safe_target(address):
    ip = ipaddress.ip_address(address)
    return ip in LAB and ip != HOST

for a in ["192.168.56.101", "192.168.56.1", "192.168.1.5", "8.8.4.4"]:
    print(a, safe_target(a))

Only 192.168.56.101 prints True. The host address is excluded because the host is your real computer, not a lab target.

Quick Quiz

1. Which network mode should you avoid for a deliberately vulnerable VM?

2. What is the default VirtualBox host-only network range?

3. Why publish a Docker port as -p 192.168.56.101:3000:3000 instead of -p 3000:3000?

4. What does a VM snapshot let you do?

Learn Cyber Security with a mentor

Free lessons get you started. Our Ethical Hacking & Cyber Security training adds real projects and code reviews from working developers.

  • Project-based learning
  • Mentor code reviews
  • Free counselling call