QuickZTNA User Guide
Home WireGuard WireGuard Penetration Testing

WireGuard Penetration Testing

What We Are Testing

Penetration testing verifies security boundaries hold from the outside. These tests run against your own machines in a controlled environment. Every test here should FAIL the attack — the attack failing is the passing grade.

What pass means in pentest: The attack fails. The system rejects, drops, or ignores the adversarial action.

Your Test Setup

Install tools on Linux-C before starting:

sudo apt install nmap tcpdump -y

ST1 — Port Scan from Public IP

What it verifies: Win-A (behind NAT) is not directly reachable from the public internet.

Steps:

  1. On Win-A, find your public IP:
(Invoke-WebRequest -Uri https://api.ipify.org).Content
  1. On Linux-C, scan Win-A public IP:
nmap -sS -T4 --top-ports 1000 YOUR_WIN_A_PUBLIC_IP
sudo nmap -sU -T4 --top-ports 200 YOUR_WIN_A_PUBLIC_IP

Expected output:

All 1000 scanned ports on x.x.x.x are filtered.

Pass: All ports filtered or unreachable. No services exposed on Win-A public IP.


ST2 — Traffic Interception Attempt (MITM)

What it verifies: On-path attacker cannot read WireGuard traffic even with packet capture.

Steps:

  1. On Linux-C, capture traffic on uplink interface:
tcpdump -i eth0 -w /tmp/intercept.pcap -n
  1. On Win-A, send 100 pings to Win-B:
ztna ping WIN_B_TAILNET_IP --count 100
  1. On Linux-C, stop capture and examine payload:
# CTRL+C to stop
tcpdump -r /tmp/intercept.pcap -A | strings | head -100
tcpdump -r /tmp/intercept.pcap -A | grep -E "(quickztna|100\.64)"

Expected output:

strings output: only binary garbage
grep: zero matches for quickztna or tailnet IPs in payload

Pass: No plaintext content in captured packets. All payload is ciphertext.


ST3 — Key File Permissions Check

What it verifies: The WireGuard private key on disk is protected by OS-level permissions.

Steps on Win-A (Windows):

ls ":APPDATA\QuickZTNA"
icacls ":APPDATA\QuickZTNA\state.json"

Steps on Linux-C:

stat /var/lib/quickztna/state.json 2>/dev/null || stat ~/.config/quickztna/state.json 2>/dev/null

Expected output:

Linux: -rw------- 1 root root (permissions 600)
Windows: Only current user has access, no World/Everyone ACE

Pass: State file is readable only by the owning user/service account.

Fail: File is 644 or 777 on Linux, or has World readable ACE on Windows — report as configuration issue.


ST4 — Replay Attack Simulation

What it verifies: WireGuards built-in replay window rejects previously-seen packet counters.

Steps:

  1. On Linux-C, capture one WireGuard packet from Win-A:
tcpdump -i any udp -c 3 -w /tmp/replay.pcap
  1. On Win-A, send a ping to trigger a packet:
ztna ping LINUX_C_TAILNET_IP --count 1
  1. On Linux-C, replay the captured packets:
sudo apt install tcpreplay -y 2>/dev/null
sudo tcpreplay --intf1=eth0 --pps=5 /tmp/replay.pcap
  1. Watch Win-A for any reaction:
ztna status
# Should show no new unexpected activity

Expected output:

# tcpreplay sends packets
# WireGuard SILENTLY DROPS all replayed packets
# Win-A shows no new pings, no session disruption

Pass: No effect on Win-A. Replayed packets are silently dropped.


ST5 — Unenrolled Peer Cannot Join Mesh

What it verifies: A machine with the ztna binary but NOT enrolled in your org cannot communicate with enrolled machines.

Steps:

  1. On a machine NOT enrolled in your org, try to reach Win-A tailnet IP:
ping 100.64.0.1
# Should get no response
  1. Try ztna commands without enrollment:
ztna peers
# Should return error or empty

Expected output:

ping: no response (tailnet IPs not routable on public internet)
ztna peers: not connected or empty

Pass: Unenrolled machine cannot reach any tailnet IP. No traffic forwarded.


Summary

Sub-testAttack attemptedPass = attack fails
ST1Port scan from internetAll ports filtered
ST2Traffic interceptionPayload is ciphertext
ST3Key file accessFiles OS-permission protected
ST4Replay attackPackets silently dropped
ST5Unenrolled peerCannot reach tailnet IPs