Build a Safe Practice Lab
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:
| Part | Suggested choice | Why |
|---|---|---|
| Hypervisor | Oracle VirtualBox, or VMware Workstation Pro | Both are free to download for personal use and run on Windows and Linux |
| Attacker VM | Kali Linux | A Debian-based distribution with hundreds of security tools preinstalled |
| Target VM | Ubuntu Server running practice apps in Docker | A normal server you can harden and attack again and again |
| Practice apps | OWASP Juice Shop, DVWA | Deliberately vulnerable web apps made for learning |
| Network | Host-only or internal network | Keeps 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.
| Mode | Who can reach the VM | Use in the lab |
|---|---|---|
| NAT | The VM can reach the internet; nothing outside can reach it | Fine for downloading updates, then switch |
| Bridged | The VM joins your real network like a separate device | Avoid for vulnerable VMs |
| Host-only | Only the host and other VMs on the same host-only network | Best for most labs |
| Internal network | Only other VMs on that internal network, not even the host | Most 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:
& "C:\Program Files\Oracle\VirtualBox\VBoxManage.exe" list hostonlyifsGive 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
- 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
kaliwith passwordkali; change it at once withpasswd. - Install Ubuntu Server as the target VM and install Docker from Ubuntu's or Docker's official instructions.
- Update both VMs before you start (
sudo apt update && sudo apt full-upgrade). - 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.
# 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-shopFor 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:
ip -brief address
ping -c 3 192.168.56.101
curl -I http://192.168.56.101:3000lo 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:
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}")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.
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}')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:3000on 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
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?
Bridged mode puts the VM on your real network, where other devices can reach it.
2. What is the default VirtualBox host-only network range?
VirtualBox's default host-only network is 192.168.56.0/24, with the host at 192.168.56.1.
3. Why publish a Docker port as -p 192.168.56.101:3000:3000 instead of -p 3000:3000?
Binding to one address keeps the vulnerable app off other networks such as public Wi-Fi.
4. What does a VM snapshot let you do?
A snapshot saves the whole machine state so you can revert after breaking something.
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
