Table of contents

Introduction

I wanted to learn offensive cybersecurity, actual technical skills, hands-on. I had time for it, but not a ton during exams and the semester, so CWES made more sense than jumping straight into CPTS. On top of that, some pentesting internships specifically value Hack The Box experience, which made the decision easy. So I planned it out: complete the path during exam season and find a 4 days timeslot during the semester.


The Exam Experience

I was pretty rusty going in. I had done about 60% of the course during the Christmas break (two months earlier) and barely took any notes. Right before the exam, I set up my environment: I spun up a fresh VM from my golden image, which is a clean base I keep updated with all my tools and only touch for upgrades. From that, I create throwaway VMs for any actual work and can insert VPN at deployment instantly.

Setup Deployment (Fedora SilverBlue)

Requirements: libvirt-client qemu-img virt-install

#!/bin/bash

VM_NAME="ParrotLab"
BASE_IMG="$PATH_TO_BASE_IMAGE"
VM_DIR="$HOME/2_lab/vms/$VM_NAME"
DISK="$VM_DIR/$VM_NAME-disk.qcow2"
CLOUD_ISO="$VM_DIR/config.iso"
SHARED_PATH="/srv/shared_disk"
VPN_FILE="${1:-}"
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"

# 1. Cleanup old attempts
virsh --connect qemu:///session destroy $VM_NAME 2>/dev/null
virsh --connect qemu:///session undefine $VM_NAME --remove-all-storage 2>/dev/null
mkdir -p "$VM_DIR"

# 2. Create the Linked Clone
echo "[+] Creating linked clone..."
qemu-img create -f qcow2 -b "$BASE_IMG" -F qcow2 "$DISK"

# 3. Build user-data (inject VPN config if provided)
USERDATA="$SCRIPT_DIR/user-data"
FINAL_USERDATA="$VM_DIR/user-data"
cp "$USERDATA" "$FINAL_USERDATA"

if [ -n "$VPN_FILE" ]; then
  if [ ! -f "$VPN_FILE" ]; then
    echo "[!] VPN file not found: $VPN_FILE"
    exit 1
  fi
  VPN_NAME="$(basename "$VPN_FILE" .ovpn)"
  echo "[+] Injecting VPN config: $VPN_FILE"

  # Write the VPN config block to a temp file
  VPN_BLOCK=$(mktemp)
  {
    echo "  - path: /etc/openvpn/client/${VPN_NAME}.conf"
    echo "    permissions: '0600'"
    echo "    content: |"
    sed 's/^/      /' "$VPN_FILE"
  } > "$VPN_BLOCK"

  # Replace placeholders in user-data
  sed -i -e "/^  #VPN_WRITE_FILES/{r $VPN_BLOCK" -e 'd}' "$FINAL_USERDATA"
  sed -i "s|  #VPN_RUNCMD|  - [ systemctl, enable, --now, openvpn-client@${VPN_NAME} ]|" "$FINAL_USERDATA"
  rm -f "$VPN_BLOCK"
else
  # No VPN — strip placeholders
  sed -i '/^  #VPN_WRITE_FILES/d' "$FINAL_USERDATA"
  sed -i '/^  #VPN_RUNCMD/d' "$FINAL_USERDATA"
fi

# 4. Generate Cloud-Init ISO using xorriso
echo "[+] Creating config ISO..."
META_DATA="$VM_DIR/meta-data"
echo "instance-id: $(uuidgen)" > "$META_DATA"
xorriso -as mkisofs \
  -R -V cidata \
  -o "$CLOUD_ISO" \
  "$FINAL_USERDATA" "$META_DATA"

# 5. Deploy
echo "[+] Deploying $VM_NAME..."
virt-install \
  --connect qemu:///session \
  --name "$VM_NAME" \
  --memory 8192 \
  --vcpus 8 \
  --cpu host-passthrough \
  --os-variant debian12 \
  --disk path="$DISK",bus=virtio \
  --disk path="$CLOUD_ISO",device=cdrom \
  --import \
  --graphics spice,listen=none \
  --video virtio \
  --network type=user,model=virtio \
  --filesystem "$SHARED_PATH",shared_disk,mode=mapped,type=mount \
  --features acpi=on,apic=on \
  --boot loader=/usr/share/edk2/ovmf/OVMF_CODE.fd,loader_ro=yes,loader_type=pflash,nvram_template=/usr/share/edk2/ovmf/OVMF_VARS.fd \
  --noautoconsole

echo "[!] Success. If it doesn't show up in Virt-Manager immediately, restart it."

Cleanup script (Fedora SilverBlue)
#!/bin/bash

VM_NAME="ParrotLab"
VM_DIR="$HOME/2_lab/vms/$VM_NAME"

echo "[!] Starting cleanup for $VM_NAME..."

# 1. Stop the VM if it is running
if virsh --connect qemu:///session list --all | grep -q "$VM_NAME"; then
    echo "[+] Stopping VM..."
    virsh --connect qemu:///session destroy "$VM_NAME" 2>/dev/null
    
    echo "[+] Undefining VM and removing NVRAM..."
    virsh --connect qemu:///session undefine "$VM_NAME" --nvram
else
    echo "[-] VM $VM_NAME not found in Libvirt."
fi

# 2. Delete the associated files
if [ -d "$VM_DIR" ]; then
    echo "[+] Deleting disk files in $VM_DIR..."
    rm -rf "$VM_DIR"
else
    echo "[-] Storage directory already gone."
fi

echo "[✓] Cleanup complete."
Here’s how the days played out:

Day Flags Notes
Day 1 0 Rough start : had to accept I needed to revisit the course
Day 2 2 First flags came in the afternoon, after 1.5 days of nothing
Day 3 5 Breakthrough, started internalizing the methodology
Day 4 2 Steady
Day 5+ Report writing

The biggest lesson: be meticulous. After day one with nothing, I realized the exam wasn’t going to reward speed, it rewarded thoroughness. The path doesn’t train you for actual black box penetration testing, be aware of that ! I went back through the course material during the exam itself, and it paid off.


How I Structured My Notes - After the exam

The most valuable thing I’d recommend is building a solid methodology folder system before you sit the exam. Here’s what mine looks like:

  • 1_Methodology/ - Maps real situations to the techniques or tools and order of operations you should follow. Think: login form → try SQL Injection, then LDAP injection, etc.
  • 2_Techniques/ - Deep dives on each technique referenced in the methodology: SQL Injection, LDAP, XSS, etc.
  • 3_Tools/ - Usage references for specific tools: Nmap, SQLmap, ffuf, etc.

The key insight is that Methodology and Techniques are separate. Methodology tells you when to use something; Techniques tell you how.

Here’s an example of what a systematic methodology section looks like in practice:

Example of systematic methodology

Port & Service Discovery

  • Full port scan → Reference: Nmap
  • Identify services, versions, OS → Whatweb

Fingerprinting

  • Check HTTP headers (Server, X-Powered-By, Set-Cookie naming)
  • Check page source for comments, frameworks, JS libs
  • Identify CMS → Reference: CMS Tool
  • Check robots.txt, sitemap.xml, .well-known/
  • Check for common files: crossdomain.xml, security.txt

Etc…